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.
Related
I have a situation where I am caching the contents of a table in the database. I am using Entity Framework 6 against an SQL Azure back-end. When the data in the table is updated.The process looks a little like this:
Receive data from UI
Insert/Update according to current state of store
Trigger Cache rebuild ( on separate service )
Then on the cache service
Clear cache
Load all entities from the table
Add the collection to the cache
The code on the data service works along these lines- this is obviously a highly abstracted version, but it shows the steps we go through:
public void UpdateProperty( int newVal )
{
SetNewPropertyVal(newVal);
TriggerUpdateEvent( newVal );
}
private void SetNewPropertyVal(int newVal)
{
using (var context = new MyContext())
{
using ( var mySet = context.Set<MyEntityType>();
{
var record = mySet.FindRecordToUpdate();
record.UpdateableFieldValue = newVal;
context.SaveChanges();
}
}
}
The problem is that although context.SaveChanges() has been called before the TriggerUpdateEvent is raised, when cache rebuild ( running in a separate, fully independent, thread against a separate instance of the DbContext ) retrieves the collection of entities, it contains the old value for the updated property. This looks like a race condition- if I put a simple Thread.Sleep(1000) in the cache refresh it works consistently, but I can't believe that is a good solution to this problem.
How do I avoid triggering a cache rebuild until the Entity Framework has actually updated the data store? I thought a transaction might do the trick, but SQL Azure doesn't seem to offer them.
In this case #ivan-stoev correctly explained that there is no reason for this code to fail synchronously. That lead me to explore the Cache rebuild process in more detail and there was a reliance on a second cache concealed away in an AutoMapper configuration that was causing the old value to show up in my searches.
So for anyone else who turns up with this problem, the bug isn't in this part of your code.
My .net web service reads an entity from the DB and sends it to a client application.
The client application modifies some fields in the entity and then submits the entity back to the server to be updated in the DB.
The surefire but laborious way to do this goes something like:
public void Update(MyEntity updatedEntity)
{
using (var context = new MyDataContext())
{
var existingEntity = context .MyEntities.Single(e => e.Id == updatedEntity.Id);
existingEntity.FirstName = updatedEntity.Name;
existingEntity.MiddleName = updatedEntity.MiddleName;
existingEntity.LastName = updatedEntity.LastName;
// Rinse, repeat for all members of MyEntity...
context.SubmitChanges();
}
}
I don't want to go down this path because it forces me to specify each and every member property in MyEntity. This is will likely break in case MyEntity's structure is changed.
How can I take the incoming updatedEntity and introduce it to LINQ to SQL whole for update?
I've tried achieving this with the DataContext's Attach() method and entered a world of pain.
Is Attach() the right way to do it? Can someone point to a working example of how to this?
Attach is indeed one way to do it.
That said...
The surefire but laborious way to do this goes something like
The right way if you ask me.
This is will likely break in case MyEntity's structure is changed
I personally would expect to modify my Update business method in case the database schema has changed:
if it's an internal change that doesn't change the business, then there is just no reason to modify the code that calls your business method. Let your business method be in charge of the internal stuff
if it's some change that require you to modify your consumers, then so be it, it was required to update the calling code anyway (at least to populate for instance the new properties you added to the entity)
Basically, my opinon on this subject is that you shouldn't try to pass entities to your business layer. I explained why I think that in a previous answer.
In this question I was having problem with saving objects that had foreign keys because Objects were build from multiple Objects connected to each other thru foreign keys but they were loaded using different context each time. For example:
using (var context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM)) {
IQueryable<Konsultanci> listaKonsultantow = from k in context.Konsultancis
select k;
}
Then somewhere else in the code there would be more context used to get more object types like Persons, Training, you name it.
Then there would be code to save it (simplified):
using (var context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM)) {
if (context.Szkolenies.Any(t => t.SzkolenieID == currentSzkolenie.SzkolenieID)) {
context.Szkolenies.Attach(currentSzkolenie);
context.ObjectStateManager.ChangeObjectState(currentSzkolenie, EntityState.Modified);
} else {
context.Szkolenies.AddObject(currentSzkolenie);
}
context.SaveChanges();
}
Usually after trying to save it there would be multiple error messages
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
or
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
and few others.
So to resolve it I have declared private EntityBazaCRM context = new EntityBazaCRM(Settings.sqlDataConnectionDetailsCRM); on top of my class and reused it all the time without putting it into using. Thanks to this action I didn't have to attach anything prior to saving or anything. I was just using same context and attached any foreign keys I wanted using currentUczestnik.Szkolenie = szkolenie; and currentUczestnik.Konsultanci = consultants;. It saved without problems.
To the question:
It works for a small GUI that I have now that isn't overcomplicated. But what if I introduce multithreading, try to get multiple values from all over the place for different objects (load object to GUI, to ListView etc) using the same Context? Won't it blow back on me hurting me severely ?
In my old code before I found out about Entity Framework I was using:
const string preparedCommand = #"SELECT ID FROM TABLE WHERE NAME = "TEST"";
using (SqlConnection varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlQuery = new SqlCommand(preparedCommand, varConnection))
using (SqlDataReader sqlQueryResult = sqlQuery.ExecuteReader())
while (sqlQueryResult.Read()) {
string id= sqlQueryResult["id"].ToString();
}
}
which basically I was using for every single time I wanted to connect to SQL. If there was no connection, it would be established, if there was connection it would be reused and no problems with multithreading.
Can someone tell me what problems I can expect from doing it the way I found out to be working? Or maybe it's best way to do it?
But what if I introduce multithreading, try to get multiple values
from all over the place for different objects (load object to GUI, to
ListView etc) using the same Context? Won't it blow back on me hurting
me severely ?
Yes, yes it will. A context is basically a thin layer on top of a database connection - which is not thread safe, so you cannot reuse the same context across threads. What you are looking for is a unit of work within which you use the same context, but once that unit of work is completed you dispose the context. Since you use your own repository implementation you will have to build the unit of work on top of those repositories.
I have to build a number of small independent applications, that can be copied to an USB device and run from there out of the box. So I was thinking to use WPF, that uses EF code first to connect to a SQL Server CE database.
My question is about what architecture I should use. Although the apps are standalone, I would still like to decouple UI from domain from data, to have a clean separation of layers. But I also don't want to make it too complex.
So, I want to have a UI layer (WPF/MVVM) that uses the underlying domain layer (domain objects with domain logic) and repositories (that use EF code first).
My question is: what pattern should I use to make EF work in this case? Is there somewhere an example that demonstrates how to implement CRUD operations in such scenario? For example, should I create one context and leave it open; or should I implement the unit of work pattern and attach objects to other context if needed?
Or would you do it in a totally different way?
Thanks for the advice!
The EF context should be open for as short time as possible. Preferably use it within a using statement.
private static void ApplyItemUpdates(SalesOrderDetail originalItem,
SalesOrderDetail updatedItem)
{
using (AdventureWorksEntities context =
new AdventureWorksEntities())
{
context.SalesOrderDetails.Attach(updatedItem);
// Check if the ID is 0, if it is the item is new.
// In this case we need to chage the state to Added.
if (updatedItem.SalesOrderDetailID == 0)
{
// Because the ID is generated by the database we do not need to
// set updatedItem.SalesOrderDetailID.
context.ObjectStateManager.ChangeObjectState(updatedItem, System.Data.EntityState.Added);
}
else
{
// If the SalesOrderDetailID is not 0, then the item is not new
// and needs to be updated. Because we already added the
// updated object to the context we need to apply the original values.
// If we attached originalItem to the context
// we would need to apply the current values:
// context.ApplyCurrentValues("SalesOrderDetails", updatedItem);
// Applying current or original values, changes the state
// of the attached object to Modified.
context.ApplyOriginalValues("SalesOrderDetails", originalItem);
}
context.SaveChanges();
}
}
There is a method called Attach, which attachs entities to a context:
private static void AttachRelatedObjects(
ObjectContext currentContext,
SalesOrderHeader detachedOrder,
List<SalesOrderDetail> detachedItems)
{
// Attach the root detachedOrder object to the supplied context.
currentContext.Attach(detachedOrder);
// Attach each detachedItem to the context, and define each relationship
// by attaching the attached SalesOrderDetail object to the EntityCollection on
// the SalesOrderDetail navigation property of the now attached detachedOrder.
foreach (SalesOrderDetail item in detachedItems)
{
currentContext.Attach(item);
detachedOrder.SalesOrderDetails.Attach(item);
}
}
http://msdn.microsoft.com/en-us/library/bb896271.aspx
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