Still extremely new to the whole MVC/LINQ thing. I'm in the processes off building a blog, and I need to build a table for the posts, and within each post build a table for the comments of that post.
To build the tables, I'm doing something like:
postsTable = (new DataContext(connectionString)).GetTable<Post>();
Unfortunately for each comments table, it does the same thing. I see DataContext(connectionString) and assume it's reconnecting every single time. I feel like I should be able to connect once at the start of the fetch and then close the connection when I'm done. Am I doing this wrong?
What your looking for is a pattern called "Session/Context per Request". The most popular and cross ORM, cross WebForms/MVC way of doing this is at the start of a request new up a context, throw in session, and finally at the end pull it down and dispose of it.
From: http://blogs.microsoft.co.il/blogs/gilf/archive/2010/05/18/how-to-manage-objectcontext-per-request-in-asp-net.aspx
public static class ContextHelper<T> where T : ObjectContext, new()
{
#region Consts
private const string ObjectContextKey = "ObjectContext";
#endregion
#region Methods
public static T GetCurrentContext()
{
HttpContext httpContext = HttpContext.Current;
if (httpContext != null)
{
string contextTypeKey = ObjectContextKey + typeof(T).Name;
if (httpContext.Items[contextTypeKey] == null)
{
httpContext.Items.Add(contextTypeKey, new T());
}
return httpContext.Items[contextTypeKey] as T;
}
throw new ApplicationException("There is no Http Context available");
}
#endregion
}
You can also mess around with new()ing up the DataContext in your controller constructor as seen here:
http://www.stephenwalther.com/blog/archive/2008/08/20/asp-net-mvc-tip-34-dispose-of-your-datacontext-or-don-t.aspx
Now this article says you don't have to worry about disposing of your context but I disagree. With modern ORMs you really want to take advantage of the "session" like ways they track and persist changes. Without manually disposing of your context all sorts of bad code or horrible unit of work patterns won't throw exceptions like they should. IMHO the session aspect of an ORM is the most important part. Ignore at your peril.
If your using SQL Server the connection pooling feature negates a lot of the performance impacts of opening and closing a connection. Unless you start doing 100,000 requests a second I wouldn't worry about it.
Go to http://www.asp.net/MVC and check out the tutorials and starter kits there are a whole bunch of good articles that will show you what you are looking for
Since you're doing LINQ to SQL you can...
Define the blogs and comments tables on your database with the appropriate foreign key relationship.
Drag and drop both onto your dbml designer surface. Click the save button; that's when the code is generated.
When you populate your viewmodel (or however you're getting your data back to the result of a controller action) only query the information you need at the time.
For a single view of a blog entry with associated comments ithe LINQ query might look like so...
YourDataContext dataContext = new YourDataContext();
var blogData = (from b in dataContext.Blogs
where b.BlogId == 1
select b).SingleOrDefault();
// you should now have a single blog instance with a property named Comments. Set the
// fetch mode to eager if you plan to always show the comments; leave it lazy to only do
// the lookup if necessary. Execute all of your queries/accesses before you pass
// data to the view
Related
I define the index API of a controller as the following:
[HttpGet]
public IEnumerable<Blog> GetDatas()
{
return _context.Blogs;
}
This always returns empty even-thought the database contains many blogs. However, when I do the following for test reasons only, entity framework manages to see the data and can return all the blogs in the database:
[HttpGet]
public IEnumerable<Blog> GetDatas()
{
var blogs = _context.blogs.ToList();
return _context.Blogs;
}
Any thoughts?
(maybe related to my other unanswered question).
Update 1
To avoid confusion around deferred execution in LINQ; I've tried the following two methods and using neither of the methods the returned json object contains the information already in the database. In other words, the serialized objects do not reflect entities persisted in the database. I think these methods would trigger execution of LINQ query, correct?
// Method 1:
[HttpGet]
public async Task<ActionResult<IEnumerable<Blog>>> GetDatas()
{
return await _context.Blogs.ToListAsync().ConfigureAwait(false);
}
// Method 2:
[HttpGet]
public IEnumerable<Blog> GetDatas()
{
return _context.Blogs.ToList();
}
As Daniel said, this is by design. See What are the benefits of a Deferred Execution in LINQ? for an extended discussion but essentially data is loaded when it is used, not when it is requested. The only way you can see that it's empty is in the debugger; your runtime code doesn't see it that way because as soon as you try and find out whether the first form is empty or not it will fill with data, at which point (the point of use) it doesn't matter that it was empty up to that point - nothing was using it to find out whether it was empty or full
Think of it a bit like Schrondinger's cat
It's quite helpful actually:
var w = worldPopulation.Where(e => e.Gender = Gender.Male)
if(name!=null)
w=w.Where(e=>e.Name == name)
The first query, if it ran immediately, could see 3.5 billion results being downloaded from your db to your client (a low spec machine compared with the server), then the name filter would reduce it to a few million. Better to only download a few million into your slow, low spec machine over a very slow network, in the first place.. right?
One benefit of only running the query when you actually ask for the data is that at that point you finally actually KNOW you want the data. Up to that point you might never have needed it, so downloading it would be a waste of resources
Use a scoped or context pool for database instead of singleton or transient; i.e., use:
services.AddDbContextPool<BlogsContext>(options => {options.UseSqlServer();});
and avoid registrations such as (note ServiceLifetime.Singleton):
services.AddDbContext<BlogsContext>(options => {options.UseSqlServer();}, ServiceLifetime.Singleton);
I have spent 2 days bashing my head against this problem, and I can't seem to crack it (the problem that is). The same code was working fine until I added database relationships, and I have since read a lot about lazy-loading.
I have two database tables with a 1:1 relationship between them. PromoCode table tracks codes, and has a PK column named id. CustomerPromo table has a column PromoId which is linked to the PromoCode table id. These two tables have no other relationships. I generated all this in SQL Server Management Studio, then generated the model from the database.
To make matters slightly more complicated, I'm doing this inside a WCF data service, but I don't believe that should make a difference (it worked before database relationships were added). After enabling logging, I always get an Exception in the log file with text:
DataContext accessed after Dispose.
My function currently returns all entries from the table:
using (MsSqlDataContext db = new MsSqlDataContext())
{
// This causes issues with lazy-loading
return db.PromoCodes.ToArray();
}
I have read numerous articles/pages/answers and they all say to use the .Include() method. But this doesn't work for me:
return db.PromoCodes.Include(x => x.CustomerPromos).ToArray();
I've tried the "magic string" version as well:
return db.PromoCodes.Include("CustomerPromos").ToArray();
The only code I've managed to get to work is this:
PromoCode[] toReturn = db.PromoCodes.ToArray();
foreach (var p in toReturn)
p.CustomerPromos.Load();
return toReturn;
I've tried added a .Where() criteria to the query, I've tried .Select(), I've tried moving the .Include() after the .Where() (this answer says to do it last, but I think that's only due to nested queries). I've read about scenarios where .Include() will silently fail, and after all this I'm no closer.
What am I missing? Syntax problem? Logic problem? Once I get this "simple" case working, I also need to have nested Includes (i.e. if CustomerPromo table had a relationship to Customer).
Edit
Including all relevant code. The rest is either LINQ to SQL, or WCF Data Services configuration. This is all there is:
[WebGet]
[OperationContract]
public PromoCode[] Test()
{
using (MsSqlDataContext db = new MsSqlDataContext())
{
return db.PromoCodes.Include(x => x.CustomerPromos).ToArray();
}
}
If I call that through a browser directly (e.g. http://<address>:<port>/DataService.svc/Test) I get a reset connection message and have to look up the WCF logs to find out "DataContext accessed after Dispose.". If I make the same query through an AJAX call in a webpage I get an AJAX error with status error (that's all!).
I prematurely posted the previous answer when I didn't actually have any child data to fetch. At the time I was only interested in fetching parent data, and that answer worked.
Now when I actually need child data as well I find it didn't work completely. I found this article which indicates that .Include() (he says Including() but I'm not sure if that's a typo) has been removed, and the correct solution is to use DataLoadOptions. In addition, I also needed to enable Unidirectional Serialisation.
And to top it off, I no longer need DeferredLoadingEnabled. So now the final code looks like this:
using (MsSqlDataContext db = new MsSqlDataContext())
{
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<PromoCode>(p => p.CustomerPromos);
db.LoadOptions = options;
return db.PromoCodes.ToArray();
}
After setting Unidirectional Serialisation it will happily return a parent object without having to load the child, or explicitly set DeferredLoadingEnabled = false;.
Edit: This did not solve the problem entirely. At the time of testing there wasn't any child data, and I wasn't trying to use it. This only allowed me to return the parent object, it doesn't return child objects. For the full solution see this answer.
Contrary to everything I've read, the answer is not to use .Include() but rather to change the context options.
using (MsSqlDataContext db = new MsSqlDataContext())
{
db.DeferredLoadingEnabled = false; // THIS makes all the difference
return db.PromoCodes.ToArray();
}
This link posted in the question comments (thanks #Virgil) hint at the answer. However I couldn't find a way to access LazyLoadingEnabled for LINQ to SQL (I suspect it's for EntityFramework instead). This page indicated that the solution for LINQ to SQL was DeferredLoadingEnabled.
Here is a link to the MSDN documentation on DeferredLoadingEnabled.
I'm building a Webforms EF6 database first application and am not sure how best to manage DbContext. I looked at a lot of tutorials and forum posts but I'm still sure. Regarding the much favored 'using per request', I've not found a way to save parent & children in one go. I got it to work with the code below, but where and when would I dispose of the context? Can I use this approach? Would the per request approach by Kamyar shown here be better?
Here's what I've got now:
public static class ContextManager
{
[ThreadStatic]
private static MyContext current;
public static MyContext MyCurrentContext
{
get{
if (current == null)
current = new MyContext();
return current;
}}
}
coupled with
var context = ContextManager.MyCurrentContext;
.....
context.SaveChanges();
Thanks in advance for any help!
A specific example would be 'UserProfile' which contains child objects as properties such as 'DefaultInvoiceAddress' which returns the user's default invoice address from a table with all the user's addresses. In the last web application I worked on, when user edits this address from within the profile (e.g. street change), together with other profile information from other tables, EF would save all edited information from the different tables in one request (ensuring they're attached). Since I wasn't privy to the context management, I don't know how it was done, but we would always assign a common current context for the requests.
I came across this post by Rick Strahl, and this one by Jordan van Gogh - the business object / transaction seem to be an answer, but I don't quite understand how to implement it and couldn't find an example. The 'shared ObjectContext instance per HTTP request' corresponds to Kamyar's answer mentioned above, and all things considered, it sounds a good option. Would I have to explicitly dispose of the context, if so when/where?. Are there any drawbacks?
Bad idea. Static is totally against the best practices. No 2 users ever will use the app at the same time? Ouch. For WebForms.
Per request IS the best choice.
The EF db context object is not, I repeat NOT threadsafe no matter how you manage it. Lots of problems can arise from sharing a db context across threads so the best way is, as mentioned above to use it per request.
If you don't want to jump into the IoC/DI side of things a really simple way to do it is whenever you need the database you just instantiate your context in a using block, like so:
using(var db = new MyContext())
{
// code reading from/writing to database
...
...
}
Using singleton pattern with entity framework database context is a design defect specially if you work with concurrency environment such as web forms because you have to take in your consideration that DbContext is not thread safe object.
I have a Data Access Layer which creates a context and retrieves data (with no object tracking) and passes the information back to UI layer:-
My unit of work is a method and I release appdatacontext after executing the particular method. So I am not keeping track of the data context anywhere..
public LinqObject GetObject(){
using (appdatacontext = new DataContext()){
---code to select and return object
}
}
I will modify data using the form in UI and submit back my data to DB.
Two approaches are:-
1. Detach and reattach to a different data context using [Detach..Serialise and Attach]
*I have to do a lot of plumping code to enable this functionality*
2. Get the DB object using primary key and make changes in the selected object and SubmitChanges.
Which one is a better approach for doing this task?
I am completely against moving the unit of work to Data Access Layer wise or Web Application Life cycle (httpcontext), because I dont want to track the changes and complicate the entire application structure with unwanted plumping code . I am just using LINQ for making my retrieval and updates to DB easy.
I have never seen anyone discuss these two approaches in LINQ context, that is why I am asking for best practice.
If you don't want to go with (2) because of performance: another option is to attach a new object to submit the updates.
Foo foo=new Foo { FooId=fooId }; // create obj and set keys
context.Foos.Attach(foo);
foo.Name="test";
context.SubmitChanges();
See my answer here.
As per #Chris's comments. I have finally arrived at the solution like:-
function void SaveRow(Table.RowObject object) {
var original=null;
using (context= new DataContext())
{
context.ObjectTrackingEnabled = false;
original = {query}.Single();
}
using(context=new DataContext()){
try
{
context.Table.Attach(object, original);
context.SubmitChanges();
}
catch (Exception exception) {
saveStatus = false;
}
}
}
I kept the update checks to ensure there is concurrency checking, if I disable that I can reduce the amount of where statement generated by Linq.
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.