Intercepting context.SaveChanges() in MVC 3 so that I can modify and use a custom sql query instead - asp.net-mvc-3

I am working on an MVC3 project whose model is designed using Code First approach. I am using EF4 for ORM and have a need where I need two thing -
1. Intercept the context.SaveChages method
2.Do my own custom update query for one specific entity type only.
I got the first part working by overriding the SaveChanges() method like -
public override int SaveChanges()
{
var modifiedItems = this.ChangeTracker.Entries().Where(e => e.State == System.Data.EntityState.Modified && e.Entity is myEntityName);
foreach (var item in modifiedItems)
{
//ToDo: Write UPDATE Sql Query here
}
return base.SaveChanges();
}
How can I write my update query?
Thanks!

This is not possible. You can only map custom stored procedures to be used instead of CUD operations (only with EDMX) generated by EF but still you will have single stored procedure call per each operation and entity instance.

Related

Linq to entities custom function in select

In Linq to Entities one can't use standard c# method to modify the results in the "select" clause, canonical functions are required.
I need to invoke such query:
CoreEntities.Contracts.Select(
c=> new {
c.Name,
c.Type,
Role = MapToRole(c));
private string MapToRole(Contract contract) {
switch(contract.Type) {
case: CTypes.Main: return "somerole1";break;
case: CTypes.Secondary: return "somerole2";break;
// ...
default: break;
}
return "none";
}
The "MapToRole" is a C# method created just to declutter the linq query.
Is there a way to create a custom c# function that would be accepted by Entity Framework "linq to Entity" parser?
I've found a solution for query filters but not for data formatting.
It appears that as it's a simple transformation, there's no reason this needs to be translated by the provider. I would suggest simply adding AsEnumerable() before your Select() to "detach" your projection from the provider.
Alternatively you could have a CTypes property in your data type and a method/property that performs the transformation of that within your model.
As a side note, doing this particular transformation in your application layer means that you're only pulling through the enum value, not a string - therefore less data from the provider.

Webapi Update Multiple Records

Which is the best approach for updating multiple records at a time using ASP.NET Web API and OData against an Entity Framework database?
Let's suppose we have a table in our database with a "State" field, and we want to do something similar to this SQL statement: "UPDATE Table set State = 1". Should I do a loop with GET and PUT for each record? I do not like it at all, I guess it must be a better way to accomplish this.
Thank you
It looks like you can't do this natively in OData, but there is one approach that will definitely work; just use a native Web API action to perform the update.
E.g.
[HttpPut]
[Route("resources/state")]
public IHttpActionResult UpdateState(int newState)
{
db.Database.SqlCommand("UPDATE Table SET State = #p0", newState);
}
You'd call this from a client using a PUT /resources/state?newState=1.
It might be clearer to make newState an enum:
public enum State
{
New = 0,
Processed = 1,
Error = 2,
etc.
}
[HttpPut]
[Route("resources/state")]
public IHttpActionResult UpdateState(State newState)
{
db.Database.SqlCommand("UPDATE Table SET State = #p0", (int)newState);
}
Then your call becomes PUT /resources/state?newState=Processed which is a little clearer.
OData supports such kinds of operations. You can use OData Action to update the state.
Blog: odata-actions-and-functions
Sample: ODataActionSample

Validate breeze save bundle before going to the breeze controller

Everywhere I look about validating the response before saving to the DB, in breeze, they are overriding the BeforeSaveEntity or BeforeSaveValidation.
e.g. breezejs issues with the save bundle. Is there anyway we can validate the savebundle before calling the saveChanges(), like in the repository level?
I want to pass the JObject savebundle from the controller to the relevant repository and do a few things there:
1) Check if the user has permission to save this entity
2) Do business-logic level validation
3) Do entity level operations such as updating the changedDate and changedUser, add default values to some other entity etc...
These are more like business-logic level operations and in our application we have like 20+ such entities that get saved from different parts of the application. If we override BeforeSaveEntity() we are doing all such business logic level validations for all entities inside the DataContext. Like
`if (entityInfo.Entity.GetType() == typeof(MyEntityTypeModel)) {
}`
I don't think if-else or case condition for 20+ entities is a good design. Besides, we have a clear separation of concerns through the use of repositories, so I think that's where this should be done.
How do we manipulate/validate the savebundle in such case?
Use the BeforeSaveEntities method ( documented here: http://www.getbreezenow.com/breeze-sharp-documentation/contextprovider). With this method you can work with ALL of the entities of a specified type without having to perform an 'if' test on each one.
Code might look something like this:
ContextProvider.BeforeSaveEntitiesDelegate = CheckFreightOnOrders;
return ContextProvider.SaveChanges(saveBundle);
private Dictionary<Type, List<EntityInfo>> CheckFreightOnOrders(Dictionary<Type, List<EntityInfo>> saveMap) {
List<EntityInfo> entityInfos;
// extract just those entities of type 'Order'
if (saveMap.TryGetValue(typeof(Order), out orderEntityInfos)) {
// then iterate over them.
foreach (var entityInfo in orderEntityInfos) {
CheckFreight(entityInfo);
}
}
return saveMap;
}

Subsonic and Automapper - dirtyColumns collection is empty therefore can't update

I'm using Subsonic 3 and Automapper on an asp.net MVC3 project.
In my HttpPost ActionResult, I'm taking my model and mapping it to my Subsonic generated entity.
The mapping works no probs, but I can't update the entity.
Upon further inspection, it is because I have no dirty columns, therefore my call to Update() fails as Subsonic doesn't think it needs to update anything.
I've re-jigged the code loads - even forcing the method to load the entity from the db again before mapping against the model. It just seems that the mapping destroys the dirtyColumns tracking. E.g. if I map after loading from the DB, and then change a random property, it doesn't get marked as a dirty column.
I've also tried using the SetIsLoaded(true) method call. No joy after mapping.
Here's my method:
[HttpPost]
public virtual ActionResult Edit(SinglePersonModel model)
{
if (ModelState.IsValid)
{
Data.Person person;
//Now Map my model to my entity - this works
Mapper.CreateMap<SinglePersonModel, Data.Person>();
person = Mapper.Map<SinglePersonModel, Data.Person>(model);
//THIS DOESN'T SET MY COLUMN TO DIRTY
person.Link = "asdjsadij";
//THIS DOESN'T SET MY COLUMN TO DIRTY EITHER
person.SetIsLoaded(true);
person.Link = "asdjsadij";
if (person.PersonId > 0)
PersonRepository.UpdatePerson(person);
else
PersonRepository.CreatePerson(person);
return RedirectToAction(MVC.SecureAdministration.Person.Index());
}
else return View(model);
}
The Static methods on my PersonRepository just call subsonic's Update() and Save() respectively.
Any ideas would be much appreciated. I'm now thinking that I may need to put some additional properties into my model to make sure that they get carried over into the entity by the automapper.
In the worst case I'll have to just not use the Automapper when mapping back to entities from the model, which would suck.
AutoMapper.Mapper.Map<SinglePersonModel, Data.Person>(model, person); - Have you tried it like this? This doesn't assign a new instance of the object but assigns it to the existing object. Just a thought. I understand the want of not loading it from the db. But figured this might help a bit :)
Thanks for that - glad to help out :)

Entity Framework, mapping Views to Tables

I have a basic view that returns the same columns as a table (give or take 1 field)
in my DAL code, i am returning a list of MyTableObject, however in some cases, i will call the view to return the same data, but from different sources.
List<MyTableObject> tableObjects = new List<MyTableObject>();
if (case1)
tableObjects = entities.MyTableObjects.Where(criteria).ToList();
else
tableObjects = entities.MyViewObjects.Where(criteria).ToList(); // <-- This will obviously break
return tableObjects;
is there a way to Map view entities to be returned as table entities? (other than having table and view implement the same interface and return that interface) i would like to keep the return type as MyTableObject.
I came across Auto Mapper, but not sure if it would be suitable for this scenario..
Looks like i found a cool solution to this..
Initially I tried to implement interface approach and run into some casting issues (using interfaces alongside my predicate builder), and also with interfaces having to create partial classes for each entity that implement the interface..
the answer.. POCOs.
Iused Poco Template for EF, and than simply edited xxxPocoGenerator.Context.tt to return MyTable object from MyViews collection (one line).
public ObjectSet<Trade> v_Trade {
get { return _v_Trade ?? (_v_Trade = CreateObjectSet<Trade>("Trades")); }
}
nice and easy..
You can write a stored procedure (or CommandText in the model, without creating DB Object) that will simply call "Select * from View". Then create Function Import for this procedure and set the return type to MyTableObject.

Resources