Can someone pitch in their opinion about pros/cons between wrapping the DataContext in an using statement or not in LINQ-SQL in terms of factors as performance, memory usage, ease of coding, right thing to do etc.
Update: In one particular application, I experienced that, without wrapping the DataContext in using block, the amount of memory usage kept on increasing as the live objects were not released for GC. As in, in below example, if I hold the reference to List of q object and access entities of q, I create an object graph that is not released for GC.
DataContext with using
using (DBDataContext db = new DBDataContext())
{
var q =
from x in db.Tables
where x.Id == someId
select x;
return q.toList();
}
DataContext without using and kept alive
DBDataContext db = new DBDataContext()
var q =
from x in db.Tables
where x.Id == someId
select x;
return q.toList();
Thanks.
A DataContext can be expensive to create, relative to other things. However if you're done with it and want connections closed ASAP, this will do that, releasing any cached results from the context as well. Remember you're creating it no matter what, in this case you're just letting the garbage collector know there's more free stuff to get rid of.
DataContext is made to be a short use object, use it, get the unit of work done, get out...that's precisely what you're doing with a using.
So the advantages:
Quicker closed connections
Free memory from the dispose (Cached objects in the content)
Downside - more code? But that shouldn't be a deterrent, you're using using properly here.
Look here at the Microsoft answer: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe
Short version of if you need to use using/.Dispose():
The short answer; no, you don't have to, but you should...
Well, It's an IDisposable, so I guess it's not a bad idea. The folks at MSFT have said that they made DataContexts as lightweight as possible so that you may create them with reckless abandon, so you're probably not gaining much though.....
First time DataContext will get object from DB.
Next time you fire a query to get the same object (same parameters).: You’ll see query in a profiler but your object in DataContext will not be replaced with new one from DB !!
Not to mention that behind every DataContext is identity map of all objects you are asking from DB (you don’t want to keep this around).
Entire idea of DataContext is Unit Of Work with Optimistic Concurrency.
Use it for short transaction (one submit only) and dispose.
Best way to not forget dispose is using ().
I depends on the complexity of your Data Layer. If every call is a simple single query, then each call can be wrapped in the Using like in your question and that would be fine.
If, on the other hand, your Data Layer can expect multiple sequential calls from the Business Layer, the you'd wind up repeatedly creating/disposing the DataContext for each larger sequence of calls. not ideal.
What I've done is to create my Data Layer object as IDisposible. When it's created, the DataContext is created (or really, once the first call to a method is made), and when the Data Layer object disposes, it closes and disposes the DataContext.
here's what it looks like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
namespace PersonnelDL
{
public class PersonnelData : IDisposable
{
#region DataContext management
/// <summary>
/// Create common datacontext for all data routines to the DB
/// </summary>
private PersonnelDBDataContext _data = null;
private PersonnelDBDataContext Data
{
get
{
if (_data == null)
{
_data = new PersonnelDBDataContext(ConfigurationManager.ConnectionStrings["PersonnelDB"].ToString());
_data.DeferredLoadingEnabled = false; // no lazy loading
//var dlo = new DataLoadOptions(); // dataload options go here
}
return _data;
}
}
/// <summary>
/// close out data context
/// </summary>
public void Dispose()
{
if (_data != null)
_data.Dispose();
}
#endregion
#region DL methods
public Person GetPersonByID(string userid)
{
return Data.Persons.FirstOrDefault(p => p.UserID.ToUpper().Equals(userid.ToUpper()));
}
public List<Person> GetPersonsByIDlist(List<string> useridlist)
{
var ulist = useridlist.Select(u => u.ToUpper().Trim()).ToList();
return Data.Persons.Where(p => ulist.Contains(p.UserID.ToUpper())).ToList();
}
// more methods...
#endregion
}
}
In one particular application, I experienced that, without wrapping the DataContext in using block, the amount of memory usage kept on increasing as the live objects were not released for GC. As in, in below example, if I hold the reference to List<Table> object and access entities of q, I create an object graph that is not released for GC.
DBDataContext db = new DBDataContext()
var qs =
from x in db.Tables
where x.Id == someId
select x;
return qs.toList();
foreach(q in qs)
{
process(q);
// cannot dispose datacontext here as the 2nd iteration
// will throw datacontext already disposed exception
// while accessing the entity of q in process() function
//db.Dispose();
}
process(Table q)
{
// access entity of q which uses deferred execution
// if datacontext is already disposed, then datacontext
// already disposed exception is thrown
}
Given this example, I cannot dispose the datacontext because all the Table instances in list variable qs **share the same datacontext. After Dispose(), accessing the entity in process(Table q) throws a datacontext already disposed exception.
The ugly kluge, for me, was to remove all the entity references for q objects after the foreach loop. The better way is to of course use the using statement.
As far as my experience goes, I would say use the using statement.
Related
I am trying to analyze what problem i might be having with unsafe threading in my code.
In my mvc3 webapplication i try to the following:
// Caching code
public static class CacheExtensions
{
public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator)
{
var result = cache[key];
if(result == null)
{
result = generator();
lock(sync) {
cache[key] = result;
}
}
return (T)result;
}
}
Using the caching like this:
// Using the cached stuff
public class SectionViewData
{
public IEnumerable<Product> Products {get;set;}
public IEnumerable<SomethingElse> SomethingElse {get;set;}
}
private void Testing()
{
var cachedSection = HttpContext.Current.Cache.GetOrStore("Some Key", 0 => GetSectionViewData());
// Threading problem?
foreach(var product in cachedSection.Products)
{
DosomestuffwithProduct...
}
}
private SectionViewData GetSectionViewData()
{
SectionViewData viewData = new SectionViewData();
viewData.Products = CreateProductList();
viewData.SomethingElse = CreateSomethingElse();
return viewData;
}
Could i run inte problem with the IEnumerable? I dont have much experience with threading problems. The cachedSection would not get touched if some other thread adds a new value to cache right? To me this would work!
Should i cache Products and SomethingElse indivually? Would that be better than caching the whole SectionViewData??
Threading is hard;
In your GetOrStore method, the get/generator sequence is entirely unsynchronized, so any nymber of threads can get null from the cache and run the generator function at the same time. This may - or may not - be a problem.
Your lock statement only locks the setter of cache[string], which is already thread safe and doesn't need to be "extra locked".
The variation of double-checked locking in the cache is suspect, I'd try to get rid of it. Since the thread that never enters the lock() section can get result without a memory barrier, result may not be entirely constructed by the time the thread gets it.
Enumerating the cached IEnumrators is safe as long as nothing modifies them at the same time. If GetSectionViewData() returns an object with immutable (as in non changing) collections, you're safe.
Your code is missing parts like how would Products be populated? Only in GetSectionViewData?
If so, then I don't see a major problem with your code.
There is however a chance that two threads generate the same data(CachedSection) for the same key, it shouldn't create a threading problem except that you are doing the work twice, so if this was an expensive operation I would change the code so it only generates it once per key. If it is not expensive, it works fine as is.
IEnumerable for Products is not touched (assuming you create it separately per thread, but the enumerator on the cache is modified for each insert operation, hence it is not thread safe. So if you are using this I would be careful about that.
I have go the oddest problem, I get an object from EF and pass it back to the Business Logic for manipulation, when finished i'm trying to save the object back to the DB, when the object is passed into the following method it's EntityState is Modified but as soon as the attach line of code is run it is set to UnChanged hence the Save will not work.
Does anyone know why EF would do this?
public void Save(IEntity entity)
{
using (var context = new eDocumentEntities())
{
using (var scope = new TransactionScope())
{
if (entity.Id != 0)
context.AttachTo(entity.EntitySet, entity);
else
context.AddObject(entity.EntitySet, entity);
context.SaveChanges();
scope.Complete();
}
}
}
Since entity change tracking is encapsulated in Context, naturally the entity loses state and other tracking stuff when it gets detached from context.
Ok I found the solution to the problem here but Ii'm more interested in an explanation, why would EF do this, seems very counter productive!?
http://geekswithblogs.net/michelotti/archive/2009/11/27/attaching-modified-entities-in-ef-4.aspx
I'm using Linq and having trouble doing something that I believe should be trivial. I want to return data from one layer so it can be used independently of linq in another layer.
Suppose I have a Data Access Layer. It knows about the entity framework and how to interact with it. But, it doesn't care who accesses it. The one interesting requirement I have is that the queries in the entity framework return projected data that is not part of the Entity Model itself. Please don't ask me to change this part of the requirement and make POCOs for each return type, as it is not the best design given the problem I am trying to solve. Below is an example.
public class ChartData
{
public function <<returnType??>> GetData()
{
MyEntities context = new MyEntities();
var results = from context.vManyColumnsOfData as v
where v.CompanyName = "acme"
select new {Year = v.SalesYear, Income = v.Income};
return ??;
}
}
Then, I would like to have an ASP.Net UI layer be able to call into the Data Access Layer to get the data in order to bind it to a control. The UI layer should have no notion of where the data came from. It should only know that it has the data it needs to bind. Below is an example.
protected void chart_Load(object sender, EventArgs e)
{
// set some chart properties
chart.Skin = "Default";
...
// Set the data source
ChartData dataMgr = new ChartData();
<<returnType?>> data = dataMgr.GetData();
chart.DataSource = data;
chart.DataBind();
}
What is the best way to send linq projected data back to another layer?
If you don't need to use the projected type statically, just return IEnumerable<object>.
Please don't ask me to change this part of the requirement and make
POCOs for each return type, as it is not the best design given the
problem I am trying to solve.
I feel like I should rightly ignore this, as the best thing to do is to return a defined type. Anonymous types are useful when they are wholly contained within the method that creates them. Once you start passing them around, it is time to go ahead and give them the proper class treatment.
However, to live within your imposed limitations, you can return IEnumerable<object> from the method and use that or var at the callsite and rely upon the dynamic binding of the control to get at the data. It's not going to help you if you need to deal with the object programmatically, but it will serve fine for databinding.
You can not return an anonymous type, so basically for this you will need POCO's even though you don't want them.
"not the best design given the problem I am trying to solve"
Could you explain what you are trying to achieve a little more? It might be possible to return some type of list containing a dictionary of items (ie rows and columns). Think something like an untyped dataset (yuck)
Your GetData method can use IEnumerable (the "old" non-generic interface) as its return type.
Any dynamic resolution (e.g. ASP.NET or XAML bindings) should work as expected, which seems to be what you want to do.
However, if you want to use the results in your code, you will probably have to resort to .NET 4's dynamic keyword.
The following example can be run in LINQPad (in "C# Program" mode) and illustrates this:
void Main()
{
var v = GetData();
foreach (dynamic element in v)
{
((string)element.Name).Dump();
}
}
public IEnumerable GetData()
{
return from i in Enumerable.Range(1, 10)
select new
{
Name = "Item " + i,
Value = i
};
}
Keep in mind that, design-wise, coding like this will make most people frown and can affect performance.
I have a LINQ object with an additional method added to it. The class has no disposable properties or methods, but FxCop is raising the error "Types that own disposable fields should be disposable" and referencing that class.
I've reduced the code this far and still receive the error:
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from wiki in context.Wikis
from pageTag in context.VirtualWikiPageTags
select new {};
return null;
}
}
}
However, if I remove EITHER of the from clauses, FxCop stops giving the error:
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from pageTag in context.VirtualWikiPageTags
select new {};
return null;
}
}
}
Or
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from wiki in context.Wikis
select new {};
return null;
}
}
}
PagePermissionSet is not disposable.
Is this a false positive? Or is the LINQ code somehow generating a disposable field on the class? If it isn't a false positive, FxCop is recommending that I implement the IDisposable interface, but what would I do in the Dispose method?
EDIT:
The full FxCop error is:
"Implement IDisposable on 'WikiPage' because it
creates members of the following IDisposable types:
'WikiTomeDataContext'. If 'WikiPage' has previously
shipped, adding new members that implement IDisposable
to this type is considered a breaking change to existing
consumers."
Edit 2:
This is the disassembled code that raises the error:
public PagePermissionSet GetUserPermissions(Guid? userId)
{
using (WikiTomeDataContext context = new WikiTomeDataContext())
{
ParameterExpression CS$0$0001;
ParameterExpression CS$0$0003;
var permissions = context.Wikis.SelectMany(Expression.Lambda<Func<Wiki, IEnumerable<VirtualWikiPageTag>>>(Expression.Property(Expression.Constant(context), (MethodInfo) methodof(WikiTomeDataContext.get_VirtualWikiPageTags)), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki") }), Expression.Lambda(Expression.New((ConstructorInfo) methodof(<>f__AnonymousType8..ctor), new Expression[0], new MethodInfo[0]), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki"), CS$0$0003 = Expression.Parameter(typeof(VirtualWikiPageTag), "pageTag") }));
return null;
}
}
Edit 3:
There does appear to be a closure class containing a reference to the DataContext. Here is its disassembled code:
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Fields
public WikiTomeDataContext context;
// Methods
public <>c__DisplayClass1();
}
My guess is that the two From clauses generate a call to SelectMany with a closure on your data context. The instance of the closure has a field to the datacontext which is causes the FxCop warning. This is nothing to worry about.
There's only one instance of your datacontext, which you clean up via the using block. Because the closure doesn't have a finalizer there's no performance or saftey implication here in the FxCop warning.
I noticed that this is a partial class. Have you checked the other implementation file for the class and see if it has an IDisposable member that is not being disposed?
I don't think the generated closure is at fault here. Closures are generated with certain attributes that should cause FxCop to ignore warnings like this.
EDIT
Further investigation by the OP showed this to be an issue with an IDisposable field being lifted into a closure.
Unfortunately there isn't a whole lot you can do about this. There is no way to make the closure implement IDisposable. Event if you could there is no way to call IDisposable on the closure instance.
The best way to approach this problem is to rewrite your code in such a way that a disposable value does not get captured in the closure. Disposable fields should always be disposed when they are finished and capturing it in a closure prevents you from doing this.
If you're returning a LINQ query from your method, consumers will iterate over the results using foreach.
When a consumer finishes a foreach loop, it internally calls dispose on the IEnumerable source (in this case, your LINQ query). This will dispose the WikiTomeDataContext.
However, if a consumer made a call to method returning a LINQ query but never iterated over the results, it would appear that enumerable would never be disposed (that is, until the garbage collector cleaned up the object). This would lead to your WikiTomeDataContext not being disposed until garbage collection.
One way you might be able to get around this problem is by calling .ToArray on the result of your LINQ query, call dispose on your context, then return the array.
Your code that gives the error uses WikiDataContext.
Your two examples that do not give an error use WikiTomeDataContext.
Maybe there is some difference between these two that is causing the error.
On Linq to SQL's DataContext I am able to call SubmitChanges() to submit all changes.
What I want is to somehow reject all changes in the datacontext and rollback all changes (preferable without going to the database).
Is this possible?
Why not discard the data context and simply replace it with a new instance?
public static class DataContextExtensions
{
/// <summary>
/// Discard all pending changes of current DataContext.
/// All un-submitted changes, including insert/delete/modify will lost.
/// </summary>
/// <param name="context"></param>
public static void DiscardPendingChanges(this DataContext context)
{
context.RefreshPendingChanges(RefreshMode.OverwriteCurrentValues);
ChangeSet changeSet = context.GetChangeSet();
if (changeSet != null)
{
//Undo inserts
foreach (object objToInsert in changeSet.Inserts)
{
context.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert);
}
//Undo deletes
foreach (object objToDelete in changeSet.Deletes)
{
context.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete);
}
}
}
/// <summary>
/// Refreshes all pending Delete/Update entity objects of current DataContext according to the specified mode.
/// Nothing will do on Pending Insert entity objects.
/// </summary>
/// <param name="context"></param>
/// <param name="refreshMode">A value that specifies how optimistic concurrency conflicts are handled.</param>
public static void RefreshPendingChanges(this DataContext context, RefreshMode refreshMode)
{
ChangeSet changeSet = context.GetChangeSet();
if (changeSet != null)
{
context.Refresh(refreshMode, changeSet.Deletes);
context.Refresh(refreshMode, changeSet.Updates);
}
}
}
Refer to Linq to SQL - Discard Pending Changes
In .net 3.0 use the db.GetChangeSet().Updates.Clear() for updated, db.GetChangeSet().Inserts.Clear() for new or db.GetChangeSet().Deletes.Clear() for deleted items.
In .net 3.5 and above the result of GetChangeSet() is now readonly, loop the collection in for or foreach and refresh every ChangeSet table like also macias wrote in his comment.
As Haacked said, just drop the data context.
You probably shouldn't keep the data context alive for a long time. They're designed to be used in a transactional manner (i.e. one data context per atomic work unit). If you keep a data context alive for a long time, you run a greater risk of generating a concurrency exception when you update a stale entity.
Calling Clear() on the Updates, Deletes and Inserts collection does not work.
GetOriginalEntityState() can be useful, but it only gives the IDs for foreign key relationships, not the actual entities so you're left with a detached object.
Here's an article that explains how to discard changes from the data context: http://graemehill.ca/discard-changes-in-linq-to-sql-datacontext
EDIT: Calling Refresh() will undo updates, but not deletes and inserts.
The Refresh will work, however you have to give the entities you want to reset.
For example
dataContext.Refresh(RefreshMode.OverwriteCurrentValues, someObject);
You can use the GetOriginalEntityState(..) to get the original values for the objects e.g. Customers using the old cached values.
You can also iterate through the changes e.g. updates and refresh the specific objects only and not the entire tables because the performance penalty will be high.
foreach (Customer c in MyDBContext.GetChangeSet().Updates)
{
MyDBContext.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, c);
}
this will revert the changes using persisted data in the database.
Another solution is to dump the datacontext you use, using Dispose().
In any case it is a good practice to override the Insert and Remove methods in the collection of e.g. Customers you use and add e.g. an InsertOnSubmit() call. This will resolve your issue with pending Insertions and Deletions.
My application is outlook style with a icon to select an active form (ListBox). Before allowing the user to change their context they have to accept changes or discard them.
var changes = db.GetChangeSet();
if ((changes.Updates.Count > 0) || (changes.Inserts.Count > 0) || (changes.Deletes.Count > 0))
{
if (MessageBox.Show("Would you like to save changes?", "Save Changes", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
db.SubmitChanges();
} else
{
//Rollback Changes
foreach (object objToInsert in changes.Inserts)
{
db.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert);
}
foreach (object objToDelete in changes.Deletes)
{
db.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete);
}
foreach (object objToUpdate in changes.Updates)
{
db.Refresh(RefreshMode.OverwriteCurrentValues, objToUpdate);
}
CurrentForm.SetObject(null); //Application Code to Clear active form
RefreshList(); //Application Code to Refresh active list
}
}
Excellent write up on here, but here is a copy and paste of the code used.
Public Sub DiscardInsertsAndDeletes(ByVal data As DataContext)
' Get the changes
Dim changes = data.GetChangeSet()
' Delete the insertions
For Each insertion In changes.Inserts
data.GetTable(insertion.GetType).DeleteOnSubmit(insertion)
Next
' Insert the deletions
For Each deletion In changes.Deletes
data.GetTable(deletion.GetType).InsertOnSubmit(deletion)
Next
End Sub
Public Sub DiscardUpdates(ByVal data As DataContext)
' Get the changes
Dim changes = data.GetChangeSet()
' Refresh the tables with updates
Dim updatedTables As New List(Of ITable)
For Each update In changes.Updates
Dim tbl = data.GetTable(update.GetType)
' Make sure not to refresh the same table twice
If updatedTables.Contains(tbl) Then
Continue For
Else
updatedTables.Add(tbl)
data.Refresh(RefreshMode.OverwriteCurrentValues, tbl)
End If
Next
End Sub
Here is how I did it. I just followed Teddy's example above and simplified it. I have one question though, why even bother with the refresh on the DELETES?
public static bool UndoPendingChanges(this NtsSuiteDataContext dbContext)
{
if (dbContext.ChangesPending())
{
ChangeSet dbChangeSet = dbContext.GetChangeSet();
dbContext.Refresh(RefreshMode.OverwriteCurrentValues, dbChangeSet.Deletes);
dbContext.Refresh(RefreshMode.OverwriteCurrentValues, dbChangeSet.Updates);
//Undo Inserts
foreach (object objToInsert in dbChangeSet.Inserts)
{
dbContext.GetTable(objToInsert.GetType()).DeleteOnSubmit(objToInsert);
}
//Undo deletes
foreach (object objToDelete in dbChangeSet.Deletes)
{
dbContext.GetTable(objToDelete.GetType()).InsertOnSubmit(objToDelete);
}
}
return true;
}
//This works for me, 13 years later using Dotnet (Core) 6:
dbContext.ChangeTracker.Clear();