NHibernate Convert query to async query - sql-server

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
}

Related

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

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.

Flutter floor database Future bool action in DAO file?

While using floor database can we set an action which will turn as a boolean like below example?
Future<bool> isItAdded(in user_id) async{
var = dbClient = await db;
List<Map> list = await dbClient.rawQuery{SELECT * FROM Users WHERE user_id}, [user_id]}
return list.lenght > 0 ? true : false
}
You may write DAO object:
#dao
abstract class UsersDao {
#Query('SELECT * FROM users WHERE user_id = :userId')
Future<List<User>> findUsers(Int userId);
}
Before that you neeed to create entity:
#Entity(tableName: 'users')
class User{
#PrimaryKey(autoGenerate: true)
final int id;
#ColumnInfo(name: 'user_id')
final int userId;
}
Also you need to create database access object:
part 'database.g.dart'; // the generated code will be there
#Database(version: 1, entities: [User])
abstract class AppDatabase extends FloorDatabase {
UsersDao get usersDao;
}
Then generate additional code by command:
flutter packages pub run build_runner build
And then write check function inside database access object:
Future<bool> isItAdded(in user_id) async {
List<User> list = await usersDao.findUsers(user_id);
return list.lenght > 0;
}
The best solution is not to add user_id column and use only unique id column.

MongoDB Compass returns all rows when I run a filter

I am trying to run a filter in MongoDB Compass and it returns all rows instead of the row that I am looking for. I can run the filter on example databases that are similar to my database without any problem.
https://i.stack.imgur.com/IBivJ.png
Here is the code that I am using to add records and select from them.
public class NoSQLDataAccess
{
// Create an instance of data factory
public NoSQLDataFactory noSQLDataFactory;
public List<dynamic> DocumentDetails { get; set; }
private IMongoCollection<dynamic> collection;
private BsonDocument bsonDocument = new BsonDocument();
public NoSQLDataAccess() { }
public void TestNoSQL()
{
MongoClient client;
IMongoDatabase database;
string connectionString = ConfigurationManager.AppSettings["NoSQLConnectionString"];
client = new MongoClient(connectionString);
database = client.GetDatabase("TestDatabase");
collection = database.GetCollection<dynamic>("TestCollection");
// Insert
List<Layer> layers = new List<Layer>();
layers.Add(new Layer { LayerId = 117368, Description = "BOOTHLAYER" });
layers.Add(new Layer { LayerId = 117369, Description = "DRAWINGLAYER" });
layers.Add(new Layer { LayerId = 117370, Description = "LAYER3" });
List<Element> elements = new List<Element>();
elements.Add(new Element { ElementId = 9250122, Type = "polyline" });
elements.Add(new Element { ElementId = 9250123, Type = "polyline" });
List<dynamic> documentDetails = new List<dynamic>();
documentDetails.Add(new DrawingDTO { Layers = layers, Elements = elements });
collection.InsertMany(documentDetails);
List<FilterDetails> filterDetails = new List<FilterDetails>();
filterDetails.Add(new FilterDetails { Type = "layers.id", Value = "117368" });
foreach (FilterDetails detail in filterDetails)
{
bsonDocument.Add(new BsonElement(detail.Type, detail.Value));
}
List<dynamic> results = collection.Find(bsonDocument.ToBsonDocument()).ToList();
}
}
I have been able to get the result I need with MongoDB shell but I have not been able to replicate the results in C#.
Here is the solution in MongoDB shell:
db.TestCollection.find({"layers.id": 117368}, {_id:0, layers: {$elemMatch: {id: 117368}}}).pretty();
I have found a post that is similar to my question that works for them. The C# code that I attached is how I will access it after I get it working properly. I use MongoDB Compass to test finds/inserts/updates/deletes.
Retrieve only the queried element in an object array in MongoDB collection

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