How can I get an item by a string key using web api? - sql-server

I can't figure out how to hit an endpoint like "api/GetItems/AB123" (AB123 of course being a string) and have it return that item from my data set. I read the docs on the FindAsync() method and it seemed to indicate that it would accept a string by default. Is there something I need to do to 'id' before passing it into FindAsync()? My DB does not have a primary key, if that matters. (I can't change that either, this is legacy data and I have no control over schema)
My db doesn't have a PK ID field. I need to do the next best thing and target a unique string field.
My GET method:
// GET: api/Items/5
[HttpGet("{id}")]
public async Task<ActionResult<Item>> GetItem(string id)
{
var item = await _context.Items.FindAsync(id); // Error happens here: "InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Int64'."
if (item == null)
{
return NotFound();
}
return item;
}
Relevant from my model:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string ItemId { get; set; }

Hello and welcome to the Stack Overflow Community!!
Instead of find you could do .SingleAsync() like the below.
You could also do a .Where(x => x.ItemId == id).SingleAsync(). But this is up to you.
// GET: api/Items/5
[HttpGet("{id}")]
public async Task<ActionResult<Item>> GetItem(string id)
{
var item = await _context.Items.SingleAsync(x => x.ItemId == id);
if (item == null)
{
return NotFound();
}
return item;
}

From your error it is obvious that int is expected in FindById method. Can you check the field type in database but from your model I would say that you don't have correct type.
String can't be used as Identity in this way because SQL Server doesn't know how to generate value for that.
You can check this post for more details on that: DatabaseGeneratedOption.Identity not generating an Id
So to conclude, you should check what do you really have in the database to determine is your model wrong.
If that is not the case and you do have a string in the db you should just retrieve item by using SingleAsync method (note that it will throw exception if the id is wrong).
var item = await _context.Items.SingleAsync(e => e.ItemId == id);
If you don't want an exception if the id doesn't exist you can use:
var item = await _context.Items.SingleOrDefaultAsync(e => e.ItemId == id);
which will return null for non existent id.

Related

Non-nullable instance field 'id' must be initialized, Non-nullable instance field '_database' must be initialized. in flutter

could anyone help me with how to manage this problem? I am trying to code exactly likes the course's video, but I got this problem:
I'm getting (Non-nullable instance field 'id' must be initialized.
Non-nullable instance field 'miles' must be initialized.
Non-nullable instance field 'name' must be initialized. Non-nullable instance field '_database' must be initialized.)
. errors in my project.
My car class:
import './dbhelper.dart';
class Car {
int id;
String name;
int miles;
Car(this.id, this.name, this.miles);
**GET ERROR FROM Car.fromMap..**
Car.fromMap(Map<String, dynamic> map) {
** Non-nullable instance field 'id' must be initialized.
Non-nullable instance field 'miles' must be initialized.
Non-nullable instance field 'name' must be initialized.**
id = map['id'];
name = map['name'];
miles = map['miles'];
}
Map<String, dynamic> toMap() {
return {
DatabaseHelper.columnId: id,
DatabaseHelper.columnName: name,
DatabaseHelper.columnMiles: miles,
};
}
}
My dbHelper.dart:
import './car.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
class DatabaseHelper {
static final _databaseName = "cardb.db";
static final _databaseVersion = 1;
static final table = 'cars_table';
static final columnId = 'id';
static final columnName = 'name';
static final columnMiles = 'miles';
** GET ERROR FROM DatabaseHelper._provateConstructor(); AND _database;
Non-nullable instance field '_database' must be initialized.**
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
** GET ERROR Non-nullable instance field '_database' must be initialized.**
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}
// this opens the database (and creates it if it doesn't exist)
_initDatabase() async {
String path = join(await getDatabasesPath(), _databaseName);
return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}
// SQL code to create the database table
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY AUTOINCREMENT,
$columnName TEXT NOT NULL,
$columnMiles INTEGER NOT NULL
)
''');
}
// Helper methods
// Inserts a row in the database where each key in the Map is a column name
// and the value is the column value. The return value is the id of the
// inserted row.
Future<int> insert(Car car) async {
Database db = await instance.database;
return await db.insert(table, {'name': car.name, 'miles': car.miles});
}
// All of the rows are returned as a list of maps, where each map is
// a key-value list of columns.
Future<List<Map<String, dynamic>>> queryAllRows() async {
Database db = await instance.database;
return await db.query(table);
}
// Queries rows based on the argument received
Future<List<Map<String, dynamic>>> queryRows(name) async {
Database db = await instance.database;
return await db.query(table, where: "$columnName LIKE '%$name%'");
}
// All of the methods (insert, query, update, delete) can also be done using
// raw SQL commands. This method uses a raw query to give the row count.
Future<int> queryRowCount() async {
Database db = await instance.database;
return Sqflite.firstIntValue(await db.rawQuery('SELECT COUNT(*) FROM $table'));
}
// We are assuming here that the id column in the map is set. The other
// column values will be used to update the row.
Future<int> update(Car car) async {
Database db = await instance.database;
int id = car.toMap()['id'];
return await db.update(table, car.toMap(), where: '$columnId = ?', whereArgs: [id]);
}
// Deletes the row specified by the id. The number of affected rows is
// returned. This should be 1 as long as the row exists.
Future<int> delete(int id) async {
Database db = await instance.database;
return await db.delete(table, where: '$columnId = ?', whereArgs: [id]);
}
}
You have to put the null aware operator in the variables type for example:
class Car {
int? id; // <---- add a ? to int so it will be int?
String? name; // <-- same here
int? miles; // <--- and here
Car({this.id, this.name, this.miles});
Car.fromMap(Map<String, dynamic> map) {
id = map['id'];
name = map['name'];
miles = map['miles'];
}
Map<String, dynamic> toMap() {
return {
DatabaseHelper.columnId: id,
DatabaseHelper.columnName: name,
DatabaseHelper.columnMiles: miles,
};
}
}
Null safety as it is explain in the dart documentation:
When you opt into null safety, types in your code are non-nullable by
default, meaning that variables can’t contain null unless you say they
can. With null safety, your runtime null-dereference errors turn into
edit-time analysis errors.
More information in: https://dart.dev/null-safety
Maybe the tutorial you are taking was previous the null aware implementation and it does not apply the null aware operators, you can do the same at the beggining of the type declartion where the error is happening in other classes, you just have to add ? to the variable type at the beginning of the variable.

NHibernate Convert query to async query

I'm looking at async-ifying some of our existing code. Unfortunately my experience with NHibernate is lacking. Most of the NHibernate stuff has been easy, considering NHibernate 5 has a lot of support for async. I am, however, stuck.
Originally, we do something like this using our Dependency Injection:
private readonly IRepository repository;
public MovieRepository(IRepository repository)
{
this.repository = repository;
}
public Movie Get(int id)
{
return (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefault();
}
//Repository Query method in Repository.cs
public IQueryable<TEntity> Query<TEntity>() where TEntity : OurEntity
{
session = session.OpenSession();
return from entity in session.Query<TEntity>() select entity;
}
This works great for our current uses. We write things this way to maintain control over our queries, especially related to more complex objects, ensuring we get back exactly what we need.
I've tried a few things, like making the Query method return a Task< List< TEntity>> and using the ToListAsync() method, however because I am returning it as that kind of list I cannot query on it.
I'm sure I've missed something. If anyone can help me out, I would appreciate it.
You need to use FirstOrDefaultAsync in this case.
public async Task<Movie> Get(int id)
{
return await (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefaultAsync();
}
Add this using statement to your file
using NHibernate.Linq;
Then you can change your method to
public async Task<Movie> Get(int id)
{
return await (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefaultAsync();
}
NB: This is only available from NHibernate 5
Addendum:
The code you have in Repository.cs can be simplified to something like this:
//Repository Query method in Repository.cs
public IQueryable<TEntity> Query<TEntity>() where TEntity : OurEntity
{
//session = session.OpenSession(); //this is obviously wrong, but it's beside the point
var session = sessionFactory.OpenSession();
return session.Query<TEntity>(); //the fix
}

EF Core Accessing Nested-nested Entity

I have an entity CallTrackerLog which has many Clients which have a one-many Advices. I am trying to HttpPost a create for the advice:
[HttpPost("{callTrackerId}/{clientId}/advice")]
public IActionResult CreateCTClientAdvice(int callTrackerId, int clientId,
[FromBody] CallTrackerClientAdvice newAdvice)
{
if (newAdvice == null)
return BadRequest();
if (!ModelState.IsValid)
return BadRequest(ModelState);
var ctFromStore = _context.CallTrackers
.Include(log => log.CallTrackerClients)
.ThenInclude(log => log.CallTrackerClientAdvice)
.FirstOrDefault(ct => ct.CallTrackerId == callTrackerId);
var ctAdviceFromStore ctFromStore.CallTrackerClients.CallTrackerClientAdvice
.FirstOrDefault(c => c.CallTrackerClientId == clientId);
// ... add to db
return Ok();
}
The problem is that I cannot access the CallTrackerClientAdvice with the .FirstOrDefault(ct => ct.CallTrackerClientId == clientId) - it gives me a red underline even though I thought I loaded it above.
The error:
How come I am unable to access the CallTrackerClientAdvice?
I suspect that what you want is:
var ctAdviceFromStore = ctFromStore.CallTrackerClients
.FirstOrDefault(c => c.CallTrackerClientId == clientId)?.CallTrackerClientAdvice;

MVC - how to retrieve multiple records in a controller

I have the following action:
public ActionResult Details(string id)
{
MyRecordContext rc = new MyRecordContext();
MyRecord r = rc.MyRecords.Single(x => x.RecordID == _id);
return View(r);
}
But turns out there are multiple records with the same id (table's primary key is a composite key). So I need to retrieve a List of type MyRecord, so I changed the code to:
public ActionResult Details(string id)
{
MyRecordContext rc = new MyRecordContext();
List<MyRecord> rl = rc.MyRecords.Any(x => x.RecordID == id);
return View(rl);
}
But the above is clearly incorrect since method Any returns bool. Can someone help me correct my code?
public ActionResult Details(String id)
{
MyRecordContext rc = new MyRecordContext();
List<MyRecord> rl = rc.MyRecords.Where(x => x.RecordID == id).ToList();
return View(rl);
}
That will return all matches with RecordID == id, then pass this list off to your view. Just make sure you update the Details view as well to accept List<MyRecord> instead of MyRecord (now that you're passing a collection).
In Linq, Any just returns a true/false is any of the values match. You are looking for a simple Where:
List<MyRecord> rl = rc.MyRecords.Where(x => x.RecordID == id);

How to return List<int> from domain service

Hello guys im using WCF RIA Services i have domain services where i wrote this method
public List<int> GetActionIDs()
{
return (from d in ObjectContext.actions select d.id).ToList();
}
How i can get this List in client side?
This does not works :
List<int> = db.GetActionIDs();
any suggestions?
First of all, you should read the RIA Services manual, because you don't realize that service calls in Silverlight are asynchronous.
In your case, you should
Add InvokeAttribute to your operation in the service:
[Invoke]
public List<int> GetActionIDs()
{
return (from d in ObjectContext.actions select d.id).ToList();
}
Then, all calls to DomainContext are asynchronous, so you get your results in the callback:
db.GetActionIDs(operation =>
{
//TODO: check the operation object for errors or cancellation
var ids = operation.Value; // here's your value
//TODO: add the code that performs further actions
}
, null);
inside DomainSrvice
[Query]
public List<Action> GetActionIDs()
{
List<Action> result = (
from a in ObjectContext.actions
select new action
{
ID = a.ID
}
).ToList();
return result ;
}
Silverlight
DomainService1 DS = new DomainService1();
LoadOperation<Action> LoadOp = Ds.Load(Ds.GetActionIDsQuery());
LoadOperation.Completed += new EventHandler((s,e)=>{
foreach (Action item in LoadOp.Entities)
{
}
});

Resources