Way to automate setting of MergeOptions - entity-framework

I am looking for an automated way to iterate over all ObjectQueries and set the merge option to no tracking (read only context). Once i find out how to do it i will be able to generate a default read only context using a T4 template. Is this possible?
For example lets say i have these tables in my object context
SampleContext
TableA
TableB
TableC
I would have to go through and do the below.
SampleContext sc = new SampleContext();
sc.TableA.MergeOption = MergeOption.NoTracking;
sc.TableB.MergeOption = MergeOption.NoTracking;
sc.TableC.MergeOption = MergeOption.NoTracking;
I am trying to find a way to generalize this using object context.
I want to get it down to something like
foreach(var objectQuery : sc){
objectQuery.MergeOption = MergeOption.NoTracking;
}
Preferably I would like to do it using the baseclass(ObjectContext):
ObjectContext baseClass = sc as ObjectContext
var objectQueries = sc.MetadataWorkspace.GetItem("Magic Object Query Option);
But i am not sure i can even get access to the queries. Any help would be appreciated.

If you wanna do it for all ObjectSet, just one time, for all exection, try this:
var Ctx=YourDbContext;
var objSetProps = Ctx.GetType().GetProperties().Where(prop => prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(ObjectSet<>));
foreach(PropertyInfo objSetProp in objSetProps)
{
ObjectQuery objSet = (ObjectQuery)objSetProp.GetValue(Ctx, BindingFlags.GetProperty, null, null, null);
objSet.MergeOption=MergeOption.NoTracking;
}

I think reflection will be the only choice for this. Something along the lines of:
IEnumerable<ObjectQuery> queries = from pd in context.GetType().GetProperties()
where pd.PropertyType.IsSubclassOf(typeof(ObjectQuery))
select (ObjectQuery)pd.GetValue(context, null);

Related

How to Use Automapper on DTO Returned From EF?

I was told to use automapper in the code below. I cannot get clarification for reasons that are too lengthy to go into. What object am I supposed to be mapping to what object? I don't see a "source" object, since the source is the database...
Would really appreciate any help on how to do this with automapper. Note, the actual fields are irrelevant, I need help with the general concept. I do understand how mapping works when mapping from one object to another.
public IQueryable<Object> ReturnDetailedSummaries(long orgId)
{
var summaries = from s in db.ReportSummaries
where s.OrganizationId == orgId
select new SummaryViewModel
{
Id = s.Id,
Name = s.Name,
AuditLocationId = s.AuditLocationId,
AuditLocationName = s.Location.Name,
CreatedOn = s.CreatedOn,
CreatedById = s.CreatedById,
CreatedByName = s.User.Name,
OfficeId = s.OfficeId,
OfficeName = s.Office.Name,
OrganizationId = s.OrganizationId,
OrganizationName = s.Organization.Name,
IsCompleted = s.IsCompleted,
isHidden = s.isHidden,
numberOfItemsInAuditLocations = s.numberOfItemsInAuditLocations,
numberOfLocationsScanned = s.numberOfLocationsScanned,
numberOfItemsScanned = s.numberOfItemsScanned,
numberofDiscrepanciesFound = s.numberofDiscrepanciesFound
};
return summaries;
}
It is a handy and a timesaver, especially if you use a one to one naming between translations layers. Here is how I use it.
For single item
public Domain.Data.User GetUserByUserName(string userName)
{
Mapper.CreateMap<User, Domain.Data.User>();
return (
from s in _dataContext.Users
where s.UserName==userName
select Mapper.Map<User, Domain.Data.User>(s)
).SingleOrDefault();
}
Multiple Items
public List<Domain.Data.User> GetUsersByProvider(int providerID)
{
Mapper.CreateMap<User, Domain.Data.User>();
return (
from s in _dataContext.Users
where s.ProviderID== providerID
select Mapper.Map<User, Domain.Data.User>(s)
).ToList();
}
It looks like you already have a model? SummaryViewModel?
If this isn't the DTO, then presumably you want to do:
Mapper.CreateMap<SummaryViewModel, SummaryViewModelDto>();
SummaryViewModelDto summaryViewModelDto =
Mapper.Map<SummaryViewModel, SummaryViewModelDto>(summaryViewModel);
AutoMapper will copy fields from one object to another, to save you having to do it all manually.
See https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
The source is your entity class ReportSummary, the target is SummaryViewModel:
Mapper.CreateMap<ReportSummary, SummaryViewModel>();
The best way to use AutoMapper in combination with an IQueryable data source is through the Project.To API:
var summaries = db.ReportSummaries.Where(s => s.OrganizationId == orgId)
.Project().To<SummaryViewModel>();
Project.To translates the properties in the target model straight to the selected columns in the generated SQL.
Mapper.Map, on the other hand, only works on in-memory collections, so you can only use it when you first fetch complete ReportSummary objects from the database. (In this case there may not be much of a difference, but in other cases it can be substantial).

Spring Data: any better way in getting the first object in an ordered list of objects?

I need to get the most recently updated object. The following is how I do it with Spring Data:
final PageRequest pr = new PageRequest(
0, 1, Direction.DESC, "updateTime"
);
List<MyObject> objects = myObjectRepository.findAll(pr);
if (objects.size() > 0) {
return objects.get(0);
} else {
return null;
}
Note that MyObject has a field called UpdateTime. A non-database-specific solution is preferred.
Thanks for any input.
--UPDATE--
I selected an answer, but not sure it is better.
Maybe you can do it via #Query annotation. http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
I suppose in your repository interface you need to define method like
#Query("SELECT o FROM MyObject o ORDER BY o.updateTime DESC LIMIT 0,1")
MyObject findMostRecentObject();
If your database doesn't support LIMIT statement you can replace it with some alternative that supports by your DB.

Best Way to convert one Edmx Entity to one Business entity

I am developing one application in which data is access from edmx entities and from that we have to fill each business entity after retriving data from edmx entity like:-
var tblproducts = tblproductsData
.Select(t => new tblProduct()
{
CategoryID = t.CategoryID,
Description = t.Description,
ID = t.ID,
Image = t.Image,
InsDt = t.InsDt,
Price = t.Price,
Quantity = t.Quantity,
Status = t.Status,
Title = t.Title,
tblCategory = new EFDbFirst.Models.tblCategory()
{
ID = t.tblCategory.ID,
status = t.tblStatus.StatusID,
Title_Category = t.tblCategory.Title_Category
},
tblStatu = new EFDbFirst.Models.tblStatu()
{
StatusDescription = t.tblStatus.StatusDescription
,
StatusID = t.tblStatus.StatusID
}
});
I am fadeup with this because everytime i have to convert one to another while getting data and setting data in db,
Is there any good way to create some common mehod which takes one anonymous type and converts it to another anonymous type.
Thanks in Advance
Your example isn't that clear.
First of all, EF doesn't work with anonymous types inside itself, it works with the EF types you have defined either using edmx file or code first. You can however create anonymous types yourself by defining an Select statement.
E.g:
var products = context.tblProductsData
.Select(r => new { Description = r.Description }); //new without typename is an
//anonymous object
The tblProduct, tblCategory and tblStatu objects, are they EF types? If so, you don't need to write a Select, EF will generate objects for you when you execute it.
E.g:
var products = context.tblProductsData.ToList();
This will automatically generate tblProduct objects for you. When you try to navigate to tblProduct.tblCategory or tblProduct.tblStatu, lazy loading will retrieve them for you. If you want to explicit load them during first query (eager-loading) use the Include function.
E.g:
var products = context.tblProductsData.Include(r => r.tblCategory)
.Include(r => r.tblStatu).ToList();
However if tblProducts, tblCategory and tblStatu is business objects and NOT EF types, there isn't any other way to do this, you have to explicit create them in a Select statement.

In Entity Framework, take a newly created object and use it to update an existing record

Here's what I'd like to do:
var myCustomer = new Customer();
myCustomer.Name = "Bob";
myCustomer.HasAJob = true;
myCustomer.LikesPonies = false;
Then I'd like to pass it into an update method:
public UpdateCustomer(Customer cust)
{
using(var context = dbcontext())
{
var dbCust = context.Customers.FirstOrDefault(c => c.Name == cust.Name);
if(dbCust != null)
{
// Apply values from cust here so I don't have to do this:
dbCust.HasAJob = cust.HasAJob;
dbCust.LikesPonies = cust.LikesPonies
}
context.SaveChanges();
}
}
The reason for this is I'm working in multiple different parts of my application, and/or across DLLs. Is this possible?
EDIT: Found this question to be immensely useful:
Update Row if it Exists Else Insert Logic with Entity Framework
If you are sure that the entity is in the database and you have key you would just Attach the object you have to the context. Note that attached entities are by default in Unchanged state as the assumption is that all the values of properties are the same as in the database. If this is not the case (i.e. values are different) you need to change the state of the entity to modified. Take a look at this blog post: http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx it describes several sceanrios including the one you are asking about.

How to create a new model entity, set its values, and save it?

I do it like this. It works but looks so ugly. And I don't have any clue to make it more meaningful.
I'm using .NET Framework 3.5 and MVC2
TRY TO Explain a little more...
With the following code, I set value to 'temp' again and again. if table 'temp' have 100 fields, then I have to set value 100 times. That's what I mean ugly.
//
// POST: /TableA/Create
[HttpPost]
public ActionResult Create(TableA formdata)
{
TableA temp = new TableA();
//A foreign key model in another TableB
var tbb = myDB.TableB.First(a => a.Id == formdata.TableB.Id);
temp.TableB = tbb;
//fields in this table
temp.field1= formdata.field1;
temp.field2= formdata.field2;
temp.field3= formdata.field3;
myDB.AddToTableA(temp);
myDB.SaveChanges();
return RedirectToAction("Index");
}
Separating code in layers usually helps, because you don't mix UI with business layer or data access layer... if that's what you asked, because it's rather hard to know what you's like to change in your code.
Otherwise your code looks as a mix of everything, becomes hard to maintain and understand what it does.
Edit
Instead of setting every property manually, you can do either:
Use object initializers (C# 3.0 feature)
TableA record = new TableA {
TableB = myDB.TableB.First(a => a.Id == formdata.TableB.Id),
Field1 = ... ,
...
};
Use static factory methods provided by entity classes:
TableA record = TableA.CreateTableA(/* provide all values as method parameters */);