I am trying to learn how to use the power of Nhibernate and after watching a turtorial i am starting to geta good grip on it.
However there is something that is bothering me.
Take for instance the following query:
var query = "SELECT * " +
"from DAGE_I_KS WHERE DATO in (:orderYear));";
var session = mySessionFactory.OpenSession();
var result = session.CreateSQLQuery(query)
.AddEntity(typeof(DAGE_I_KS))
.SetString("orderYear", "2012")
.List<DAGE_I_KS>();
Now for this to work i have to do the following steps:
Create an xml file that maps the object i want to use
Create the object class file
Create the query and execute it and insert the result into the object (or a list)
Now i have to do this for every single query i want to do. In a program you will most likely do 10+ query (if not more) which means that i have to do these steps 10 times.
For me it seems ilogical. And i am having a hard time understanding how this can save me some time and trouble.
My question is, is this correct that i have to do this every time or is there something ive missed and is there a better way to do use Nhibernate when you have costum querys.
Runtime NH revolves around the concept of a session (ISession). As you know, you get the session from the session factory.
The session is the central object through which you interact with NH to execute queries and save data. The session has a flush mode property.
It is important to know that all the entities that you get from the session by using a query are linked to that session. So, if you modify an entity which is fetched, even if you do not explicitly call session.Update(obj), when the session is flushed these changes will be persisted. Thus it follows that the only methods of the session which you actually must call are session.saveOrUpdate(obj) and session.delete(obj), because you must register newly created entities with the session, and you must register entities for deletion. When the session is flushed, these changes will be persisted.
Try to read about the session flush modes, and also the ITransaction interface.
Now, how is this related to queries?
Well, I have learned that it is best to encapsulate queries into query objects. Is not my idea, but something I picked up from the blog of Fabio Maulo, or Ayende not sure but searching for the term query object in conjuncture with NH should be informative, and if you find out who to credit with the idea I will update the answer :)
It is clear that the query object needs the session to work. So, you must write the plumbing to give it one. In my implementation, a query object would be simply:
public class ShiftByNameWithOccurences : AbstractQueryObject<IList<Shift>>
{
private string Name;
public ShiftByNameWithOccurences(string name)
{
this.Name = name;
}
public override IList<Shift> GetResult()
{
var list =
(
from shift in this.Session.Query<Shift>()
where shift.Name == this.Name
select shift
)
.Fetch(p => p.Occurrences)
.ToList();
return list;
}
}
Obviously, it is easy to implement a generic by name query for all your db entities.
In this example, the occurrences of the shift are eagerly loaded, to avoid the N+1 select problem.
It is easy to see how having encapsulated queries can benefit your OO driven app design.
Also, since you have the ISession instance, you can use what ever query method of NH that you choose.
For reference:
public abstract class AbstractQueryObject<TResult> : IQueryObject<TResult>
{
protected ISession Session;
public void Configure(object parameter)
{
if (!(parameter is ISession))
throw new ArgumentException(String.Format("Argument of wrong type. Expecting {0} but got {1}.", typeof(ISession), parameter != null ? parameter.GetType().ToString() : "null"), "parameter");
this.Session = parameter as ISession;
}
public abstract TResult GetResult();
}
public interface IQueryObject<TResult>
{
void Configure(object parameter);
TResult GetResult();
}
Even, this interface is imagined to not be linked to NH, but also so that you can use it with EF, or some other future ORM if needed. The abstract query object is in the x.NH namespace :)
Edit:
For the task of logging SQL of each query I can suggest to use interceptors to log sql.
Register a per session interceptor when you create a session. For this task you should register only one interceptor object with the session. Then, when you instantiate the query object pass in the interceptor object as a constructor argument, or in the configure method whichever you like. When the query is being executed (in get result method) - at the start tell to the interceptor object that you want to start listening. In the implementation of your interceptor create code which will then forward all the sql to the listening query object. In the query object create a custom xml using the sql. When the query is finished, unregister the query object from the interceptor object.
But keep in mind that if additional lazy loading sql statements are executed after the query object exits the get result method will not be logged.
E.g.:
public class UseCase
{
public void Method()
{
//when instantiating a session pass the interceptor to it.
//then, also pass this sniffer to the query objects you create.
//make the query objects listeners.
//when the query object is to be executed (start of the get result method)
//call the set active listener method on the sniff notifier given to the q.o.
//in the on prepare statement method of the q.o. do whatever with the sql.
SqlSniffer myInterceptor = new SqlSniffer();
var session = this.SessionFactory.OpenSession(myInterceptor);
}
}
public interface ISqlSniffListener
{
void OnPrepareStatement(string sql);
}
public interface ISqlSniffNotifier
{
void SetActiveListener(ISqlSniffListener listener);
}
public class SqlSniffer : EmptyInterceptor, ISqlSniffNotifier
{
private ISqlSniffListener ActiveListener;
public void SetActiveListener(ISqlSniffListener listener)
{
this.ActiveListener = listener;
}
public override NHibernate.SqlCommand.SqlString OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
{
if (this.ActiveListener != null)
this.ActiveListener.OnPrepareStatement(sql.ToString());
return base.OnPrepareStatement(sql);
}
}
Or even better, it is probably better to implement a listener which is not integrated in the query object (to honor SRP) .. but you would have to signal to it which query is being executed then...which can be easy if you had an object responsible for executing the query objects, which provides them the session, and also possibly creates it ;)
P.S.
It was Ayende who I read discussing the q.o., but the idea seems older.
Related
Update: #StriplingWarrior's answer has set me on the right track, but I have new questions detailed in this post.
In my organization there are three different groups using three different databases. The schema of the databases are the same -- same table structure, relational logic, etc -- and the three groups need me to report on their data in my application in the same way.
I understand that in my application I need to create a separate data context for each database, and in my repositories I need to explicitly declare the data context(s) used by that repository. I'm fine with all of that.
But if all three repos need to run the same given method, just against different data contexts, do I really need to write the same method three times? Is there no way that I can put my method in a class library, say, or some other fourth file, and then run the method against the context I need to use as and when?
For example, my repo looks like this:
public interface IMyRepo
{
List<string> GetMyData();
}
public class MyRepo : IMyRepo
{
private readonly ContextA _context;
public MyRepo(ContextA context) {
_context = context;
}
public List<string> GetMyData()
{
//code to get my data and return it
}
}
Now remember that because of the way my org's database is setup, I need to write this repo three times, once for each group. All that changes is the context.
I'd like to take the actual code for method GetMyData() and move it to a fourth file, then just link my repo to that file and call the method through an object reference, passing the context as a parameter, say. So I could call GetMyData() from my repo above like this:
//method call in my context above
public List<string> GetMyData()
{
//call actual GetMyData() method in my linked file
return linkedFile.GetMyData(_context);
}
Is something even remotely like I describe possible?
EDIT: I was asked by #RStevoUK to provide a code example for the linked file I describe, so I'll try to explain here.
So in my context I have the method GetMyData(), which runs certain code and returns a list object. In the .NET Framework days, I could put the actual code for GetMyData() into a separate class file, and then pass in the ConnectionString object that the method would use to connect to the correct database and retrieve its data.
CLASS:
public class ExternalClassFile
{
public List<string> GetMyData(string connectionString)
{
using (SqlConnection connectionString)
{
//code to get my data and return it
}
}
}
Then, to run this method against a given database, all I would need to do is call an instance of the class, and invoke the method with the correct connection string:
ExternalClassFile ecf = new ExternalClassFile();
public List<string> CallSharedMethod()
{
string connection = \\connecting string code;
return ecf.GetMyData(connection);
}
I don't think I can do that with MVC; what I understand of it leads me to believe I can't. Also, I don't think Generics are what I want, since GetMyData() would contain an actual linq query
var data = (from d in _context.DatabaseTable_Model
select d).ToList();
for example. That "_context" variable references my datacontext, and that's all that changes.
I've tried to setup a "_context" variable using a "var" declaration instead of a specific context name, but MVC doesn't like that. Is there something else I can try that would make the above linq example reusable among multiple contexts?
I hope this makes more sense.
What I'm hearing is that the only difference between your three repositories would be the specific type of DbContext that gets injected into them. And the only reason you're stuck being tightly coupled to a given type is that you have code accessing a property on that type, like _context.DatabaseTable_Model.
You can typically rewrite your data access code to rely on DbSet<> instead of a specific DbContext type. And you can get a generic DbSet<> off of any DbContext by calling its DbContext.Set<>() method.
var baseQuery = var data = _context.Set<DatabaseTable_Model>();
var data = (from d in baseQuery
select d).ToList();
Then you can make your repo take any type of DbContext:
private readonly DbContext _context;
public MyRepo(DbContext context) {
_context = context;
}
However, it's worth challenging the assumption that you need three separate data context types in the first place. If the schemas of the databases are literally the same, then the only difference between these classes should be their name, right? And the only reason the name matters is because DbContext's default constructor uses naming conventions to decide how to find the connection string to use.
DbContext has other constructors, though, so if you make your context class use one of those other constructors it should be perfectly possible to construct separate instances of the same class pointing at different databases by passing in the name of the connection string (or the actual connection string, or the connection itself) that you want it to use.
If you query the DbSet of a DbContext, the query is valid until the DbContext is disposed. The following will lead to an exception:
IQueryable<Video> allVideos = null;
using (var context = new MyDbContext())
{
allVideos = context.Videos;
}
var firstVideo = allVideos.first();
Apparently the used DbSet is stored somewhere in the returned object that implements the IQueryable.
However, MSDN advises (Link)
When working with Web applications, use a context instance per request.
Of course I could use ToList() and return the result as a list of objects, but this is rather undesirable because I don't know the reason for the query.
Example: Suppose my database has a collection countries, which have cities, which have streets, which have houses, which have families which have persons which have names.
If someone asks for the IQueryable, then it could be that he wants to search for the name of the oldest person living on Downing Street nr 10 in London in the United Kingdom.
If I returned the sequence with a ToList(), all cities, streets, houses, persons, etc would be returned, which would be quite a waste if he only needed the name of this one person. That's the nice thing about deferred execution of Linq.
So I can't return ToList(), I have to return the IQueryable.
So what I'd like to do, is open a new DbContext, and somehow tell the query that it should use the new DbContext:
IQueryable<Video> allVideos = null;
using (var context = new MyDbContext())
{
allVideos = context.Videos;
}
// do something else
using (var context = new MyDbContext())
{
// here some code to attach the query to the new context
var firstVideo = allVideos.first();
}
How to do this?
The local guru happened to pass by. He explained to me that the error in my design was that I already use a DbContext while I am only composing the query. My interface should be such that I only need the DbContext when actually materializing the requested objects.
The question was a simplified version of the following:
I have a DbContext, with several public DbSet properties. These properties mirror the actual database. I want to hide the actual database implementation in my Abstract Database Layer in order to protect my data. I don't want anyone to give access change the contents of the database without having checked whether these contents are correct.
This is easy: just don't expose your actual DbContext to the outside world, but expose a facade that hides the actually used DbContext. This facade communicates with the actual DbContext.
With most functions that return an IQueryable I need the DbContext to access the DbSets. That's why I thought to create a context, construct the query and Dispose the context. But because of the deferred execution the context is still needed.
The solution
The solution is not to create your own context, but let the caller construct the DbContext. This constructed DbContext will be one of the parameters of the function. In that case the external user can call several functions of my facade to concatenate the query, even mix with his own Linq queries on the DbContext without creating and disposing the context. So like others suggested:
Callers creates the dbContext
Caller calls several of my functions that return a query, pass the dbContext as parameter
Caller executes the query by using ToList() / ToArray() / First() / Count() etc.
Caller disposes the context
To make it even nicer, the dbContext parameter is used in an extension method:
public static IQueryable<Video> GetObsoleteVideos(this MyDbContext dbContext)
{
// perform several difficult Linq statements on context
// that will return all obsolete videos
return ...
}
public static IQueryable<Video> GetThrillerVideos(this MyDbContext dbContext)
{
return dbContext.Videos.Where(video => video.Genre == VideoGenre.Thriller);
}
usage:
using (var myContext = new MyDbContext())
{
var difficultQuery = myContext.GetObsoleteVideos()
.Where(video => video.Name == ...)
.GetThrillerVideos()
.Take(10);
// Note: the query still deferred, execute it now, before Disposing myContext
var result = difficultQuery.ToList();
}
This way (and especially if I create an interface) I am able to prohibit access to my DbSets. I am even free to internally reorganize my Db and DbContext without external users noticing anything.
There are methods in the object context to do this:
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
objectContext.Detach(entity);
objectContext.Attach(entity);
However, as it says in the quote from MSDN, you should use one instance of the EF context per request. This refers to the HttpRequest not to a single query. When you do operations in one request, you should not put using blocks around your EF context and you should extend its lifetime. For new requests, it is advisable not to keep states across requests but rather follow the protocol
Query the item again and reload (another request might have modified it in the meantime)
Make the modifications
Save
I have a number of static methods that perform simple operations like insert or delete a record. All these methods follow this template of using:
public static UserDataModel FromEmail(string email)
{
using (var db = new MyWebAppDataContext())
{
db.ObjectTrackingEnabled = false;
return (from u in db.UserDataModels
where u.Email == email
select u).Single();
}
}
I also have a few methods that need to perform multiple operations that use a DataContext:
public static UserPreferencesDataModel Preferences(string email)
{
return UserDataModel.Preferences(UserDataModel.FromEmail(email));
}
private static UserPreferencesViewModel Preferences(UserDataModel user)
{
using(var db = new MyWebAppDataContext())
{
var preferences = (from u in db.UserDataModels
where u == user
select u.Preferences).Single();
return new UserPreferencesViewModel(preferences);
}
}
I like that I can divide simple operations into faux-stored procedures in my data models with static methods like FromEmail(), but I'm concerned about the cost of having Preferences() invoking two connections (right?) via the two using DataContext statements.
Do I need to be? Is what I'm doing less efficient than using a single using(var db = new MyWebAppDataContext()) statement?
If you examine those "two" operations, you might see that they could be performed in 1 database roundtrip. Minimizing database roundtrips is a major performance objective (second to minimizing database io).
If you have multiple datacontexts, they view the same record differently. Normally, ObjectTracking requires that the same instance is always used to represent a single record. If you have 2 DataContexts, they each do their own object tracking on their own instances.
Suppose the record changes between DC1 observing it and and DC2 observing it. In this case, the record will not only have 2 different instances, but those different instances will have different values. It can be very challenging to express business logic against such a moving target.
You should definately retire the DataContext after the UnitOfWork, to protect yourself from stale instances of records.
Normally you should use one context for one logical unit of work. So have a look at the unit of work pattern, ex. http://dotnet.dzone.com/news/using-unit-work-pattern-entity
Of cause there is some overhead in creating a new DataContext each time. But its a good practice to do as Ludwig stated: One context per unit of work.
Its using connection pooling so its not a too expensive operation.
I also think creating a new DataContext each time is the correct way but this link explains different approaches for handling the data context. Linq to SQL DataContext Lifetime Management
I developed a wrapper component that uses an interface like:
public interface IContextCacher {
DataContext GetFromCache();
void SaveToCache(DataContext ctx);
}
And use a wrapper to instantiate the context; if it exists in cache, it's pulled from there, otherwise, a new instance is created and pushed to the Save method, and all future implementations would get the value from the getter.
Depending on the type of application would be the actual caching mechanism. Say for instance, an ASP.NET web application. This could store the context in the items collection, so its alive for the request only. For a windows app, it could pull it from some singleton collection. It could be whatever you wanted under the scenes.
I am working on converting a web application over to a WPF desktop application. I want to use the existing data access layer so I don't have to rewrite all the SQL queries.
But, as it stands, everything is populated almost purely from DataTables returned from SQL queries. To make things a bit easier to manage, in some instances, it would really be nice to convert these things into objects.
For example, I have a query that pulls out report information. I may get 500 results with columns like ReportID, ReportTitle, ReportDate.
I would like to make a report class that has these public attributes and somehow convert the SQL query results into a collection of these report objects.
What is the best way to go about doing this?
Super bonus points if there is an easy way of going backwards (updating the database if the objects are changed).
You should learn about Object-Relational Mapping (ORM). A good ORM can save you tonnes of work in the future, and gets those nasty queries out of your code.
I'd recommend NHibernate or Entity Framework 4.0
While I would also like to suggest ORM (NHibernate is the way to go:)) a possible solution is:
public IEnumerable<Report> ToReportList(DataTable dt)
{
return dt.AsEnumerable().Select(dr => new Report
{
member1 = dr["column1"].ToString(),
...
});
}
Report is your class here by the way.Such as,
internal class Report
{
public string member1{ get; set;}
...
}
You may also want to check this,
http://msdn.microsoft.com/en-us/library/Bb399375(v=VS.100).aspx
I think if you search stackoverflow, you will find nicer examples as I remember learning this from here.
By the way, if you use NHibernate, you won't have to rewrite your queries at all. All you have to do is map your tables to a class and booya you are good to go. It will handle all your DML stuff (well mostly) and you can easily tell the ORM to do LazyLoad, Batch processing etc which is pretty cool.
Super bonus points if there is an easy
way of going backwards (updating the
database if the objects are changed).
For that , go for ORM i.e. NHibernate (I know I am biased :)). For LINQ to SQL examples check the 2 links below:
http://msdn.microsoft.com/en-us/library/bb386931.aspx
http://csainty.blogspot.com/2008/01/linq-to-sql-insertupdatedelete.html
+1 ORM. Entity Framework is good, LINQ to SQL is good too, but you'd need a good database design and is better for pretty basic SQL CRUD actions. For custom entities from multiple datasources, I'd go EF.
As far as backwards updating - LINQ to SQL has an easy-peasy implementation, sorta like this - say you've got a db called MyDatabase with Dog entities in it:
using(MyDatabaseDataContext db = new MyDatabaseDataContext())
{
//LINQ will automatically pluralize your items (entity named Dog becomes Dogs)
Dog d = db.Dogs.Where(x=>x.DogName.Equals(dogName));
d.Owner = "Steve";
db.SubmitChanges();
//adding new items is easy too
Dog newdog = new Dog();
newDog.DogName = "Scruff";
newDog.Owner = "Jim";
db.Dogs.Add(newDog);
db.SubmitChanges();
}
Check out this method. First you can create a class that inherits DataContext. And then you can use methods of DataContext like to ExecuteQuery<> to convert your results in to objects. With this method you can directly use your queries you wrote earlier. Also, I feel that this way is a lot better than maintaining a .dbml file, because of the issues associated to synchronization with the actual database schema.
Consider the following example. First you need to define a class for interacting with your database
public class DBManagerDataContext : DataContext
{
private static string connectionString = ""; // Your connection string
public static DBManagerDataContext CreateInstance()
{
return new DBManagerDataContext(connectionString);
}
protected DBManagerDataContext(string connectionString)
: base(connectionString, new AttributeMappingSource())
{
}
}
Then you can use this context to execute queries and convert them in to objects as shown below:
public class Report
{
public int ReportID;
public string ReportTitle;
public DateTime ReportDate;
private static string query = "select ReportID, ReportTitle, ReportDate from dbo.Reports"; // Your query
public static List<Report> GetReportList()
{
DBManagerDataContext context = DBManagerDataContext.CreateInstance();
return context.ExecuteQuery<Report>(query).ToList();
}
}
You can use the method "GetReportList()" given above like this for example:
List<Report> reports = Report.GetReportList();
In the case of updates, the method suggested by "jdandison" is a nice option, apart from using the data context as above. In the case of updates it would be "ExecuteCommand" though. Please explore the DataContext class for more information.
Edit: Please note that the query column names should match the definition in the object
I have started using Linq to SQL in a (bit DDD like) system which looks (overly simplified) like this:
public class SomeEntity // Imagine this is a fully mapped linq2sql class.
{
public Guid SomeEntityId { get; set; }
public AnotherEntity Relation { get; set; }
}
public class AnotherEntity // Imagine this is a fully mapped linq2sql class.
{
public Guid AnotherEntityId { get; set; }
}
public interface IRepository<TId, TEntity>
{
Entity Get(TId id);
}
public class SomeEntityRepository : IRepository<Guid, SomeEntity>
{
public SomeEntity Get(Guid id)
{
SomeEntity someEntity = null;
using (DataContext context = new DataContext())
{
someEntity = (
from e in context.SomeEntity
where e.SomeEntityId == id
select e).SingleOrDefault<SomeEntity>();
}
return someEntity;
}
}
Now, I got a problem. When I try to use SomeEntityRepository like this
public static class Program
{
public static void Main(string[] args)
{
IRepository<Guid, SomeEntity> someEntityRepository = new SomeEntityRepository();
SomeEntity someEntity = someEntityRepository.Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));
Console.WriteLine(someEntity.SomeEntityId);
Console.WriteLine(someEntity.Relation.AnotherEntityId);
}
}
everything works nicely until the program gets to the last WriteLine, because it throws an ObjectDisposedException, because the DataContext does not exist any more.
I do see the actual problem, but how do I solve this? I guess there are several solutions, but none of those I have thought of to date would be good in my situation.
Get away from the repository pattern and using a new DataContext for each atomic part of work.
I really would not want to do this. A reason is that I do not want to be the applications to be aware of the repository. Another one is that I do not think making linq2sql stuff COM visible would be good.
Also, I think that doing context.SubmitChanges() would probably commit much more than I intended to.
Specifying DataLoadOptions to fetch related elements.
As I want my Business Logic Layer to just reply with some entities in some cases, I do not know which sub-properties they need to use.
Disabling lazy loading/delayed loading for all properties.
Not an option, because there are quite a few tables and they are heavily linked. This could cause a lot of unnecessary traffic and database load.
Some post on the internet said that using .Single() should help.
Apparently it does not ...
Is there any way to solve this misery?
BTW: We decided to use Linq t0 SQL because it is a relatively lightweight ORM solution and included with the .NET framework and Visual Studio. If the .NET Entity Framework would fit better in this pattern, it may be an option to switch to it. (We are not that far in the implementation, yet.)
Rick Strahl has a nice article about DataContext lifecycle management here: http://www.west-wind.com/weblog/posts/246222.aspx.
Basically, the atomic action approach is nice in theory but you're going to need to keep your DataContext around to be able to track changes (and fetch children) in your data objects.
See also: Multiple/single instance of Linq to SQL DataContext and LINQ to SQL - where does your DataContext live?.
You have to either:
1) Leave the context open because you haven't fully decided what data will be used yet (aka, Lazy Loading).
or 2) Pull more data on the initial load if you know you will need that other property.
Explaination of the latter: here
I'm not sure you have to abandon Repository if you go with atomic units of work. I use both, though I admit to throwing out the optimistic concurrency checks since they don't work out in layers anyway (without using a timestamp or some other required convention). What I end up with is a repository that uses a DataContext and throws it away when it's done.
This is part of an unrelated Silverlight example, but the first three parts show how I'm using a Repository pattern with a throwaway LINQ to SQL context, FWIW: http://www.dimebrain.com/2008/09/linq-wcf-silver.html
Specifying DataLoadOptions to fetch related elements. As I want my Business Logic Layer to just reply with some entities in some cases, I do not know which sub-properties they need to use.
If the caller is granted the coupling necessary to use the .Relation property, then the caller might as well specify the DataLoadOptions.
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Entity>(e => e.Relation);
SomeEntity someEntity = someEntityRepository
.Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"),
loadOptions);
//
using (DataContext context = new DataContext())
{
context.LoadOptions = loadOptions;
This is what I do, and so far it's worked really well.
1) Make the DataContext a member variable in your repository. Yes, this means you're repository should now implement IDisposable and not be left open... maybe something you want to avoid having to do, but I haven't found it to be inconvenient.
2) Add some methods to your repository like this:
public SomeEntityRepository WithSomethingElseTheCallerMightNeed()
{
dlo.LoadWith<SomeEntity>(se => se.RelatedEntities);
return this; //so you can do method chaining
}
Then, your caller looks like this:
SomeEntity someEntity = someEntityRepository.WithSomethingElseTheCallerMightNeed().Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));
You just need to make sure that when your repository hits the db, it uses the data load options specified in those helper methods... in my case "dlo" is kept as a member variable, and then set right before hitting the db.