Return the uniqueidentifier with entity framework - c#

I am using Entity Framework 3.5, while inserting a record i want to return the unique identifier with entity framework. How to do that?

After calling savechages the new id will be stored in the entity. so you can retrieve from the entity.

More generally, "To ensure that objects on the client have been updated by data source-side logic, you can call the Refresh method with the StoreWins value after you call SaveChanges.", per MSDN.
http://msdn.microsoft.com/en-us/library/bb738618.aspx

One way that I have taken to working is, when sending a record to my DataLayer/Business Logic Layer, is to have the DL/BLL do the update/insert, then retrieve the record back from the DB and return it with a boolean indicating success or failure.
That way, I can immediately refresh the record in the interface with the written one so I can be sure the record actually went in how it should have.

Related

Passing model to Data Layer for two or three parameters in Angular

I am working on an Angular (v6) project on ASP.NET MVC for backend and Entity Framework. Sometimes a have some CRUD operations that updates only 2-3 fields on an entity and in this situation I may be confused about which approach would be better for best practices for this scenario. As an example, let's say I have a Employee entity with the following properties shown below:
Employee: Id, Status, Name, Surname, Job, Department, HireDate, BirthDate, Address, Updated...
Assuming update for Status, Department and Updated field, I can perform this for the following approaches:
Approach I:
I can create an instance of employee.ts file and fill it in component.ts by only the fields to be updated and then pass it to service.ts and pass to the Controller.cs. In the Controller I receive the model as Employee entity model and set Updated field in the Controller and pass this Employee entity to the Service.cs and then save this entity using the related EF methods.
Approach II:
I just send Id, Status and Department values from Component.ts to service.ts and then pass to the Controller as int values (Id's). Then in the controller create a new instance of the Employee.cs entity and fill these 3 fields and Updated field. Then pass this entity to the Service.cs and then save this entity using the related EF methods.
Approach III:
Same as approach II until Controller.cs. Then pass these 3 parameters to the Service ts and then retrieve the Employee from database via the Id parameter. Then set the other fields and save the entity.
I think 3 of them can be used but not sure which one is better for this scenario in Angular projects with EF? Any help would be appreciated...
Approach 3, or
Approach 4:
Create an UpdateEmployeeViewModel with the PK & fields you want to update to populate in your TS, pass to the controller which validates the data, loads the entity, transfers the appropriate values and saves. When it's one or two columns then Approach 3 is fine. If it grows to more than that then I typically opt for #4.
I would avoid approach 1 at all costs. It is too convenient to have code trust the entity passed from the client. The call to your service can be intercepted and adjusted so if you server code accepts an entity you may easily find code that does a DbSet.Update or DbSet.Attach which could result in tampered data being persisted to the database.
Approach 2 also leaves issues when performing updates as an entity should always reflect its data row. Creating an entity and only partially filling it then attempting to update the data state could result in unintentional updates such as clearing out values. Down the road you may have other common methods that would accept an entity as a parameter but you have cases where the passed entity may be complete (loaded from DB) vs. incomplete (constructed by an update method)
Loading an entity by ID is quite fast so there is rarely a need to over-optimize. It also can help to check the row version # to ensure that the version of the entity you are updating matches the version still in the DB. (Did someone else update this row since you initially sent it to the client?)

Entity Framework concurrency issue using stored procedures

I am using ASP.NET to build a application for a retail company. I am using the Entity Framework (model-first) as my data access layer. I am using stored procedures to do my CRUD operations and all columns are mapped and seems to be correct as all CRUD functionality are working as expected.
But I am having concurrency issues with the DELETE operation.
I've added a TimeStamp column to the table I am doing the CRUD operation on. The UPDATE operation works fine as it is updating by primary key and the TimeStamp value. Thus if no rows are affected with the UPDATE operation, because of a change in the TimeStamp value, the Entity Framework throws a OptimisticConcurrencyException.
The DELETE operation works on the same principle as it is deleting by primary key and the TimeStamp value. But no exception is thrown when the TimeStamp value does not match between the entity and the database.
In the C# delete method I do retrieve the latest record first and then update the TimeStamp property to another TimeStamp value (It might be different to the retrieved value). After some investigation by using SQL Profiler I can see that the DELETE stored procedure is executed but the TimeStamp parameter that is passed to the stored procedure is the latest TimeStamp value and not the value that I have set the TimeStamp property to. Thus the record is deleted and the Entity Framework does not throw an exception.
Why would the Entity Framework still pass the retrieved TimeStamp value to the Stored Procedure and not the value that I have assigned the property? Is this be design or am I missing something?
Any help will be appreciated! (where is Julie Lerman when you need her! :-))
Optimistic concurrency in EF works fine. Even with stored procedures.
ObjectContext.DeleteObjects passes original values of entity to delete function. This makes sense. Original values are used to identify the row to delete. When you delete object, you don't (usually) have meaningful edits to your entity. What do you expect EF to do with then? Write? To what records?
One legitimate use for passing modified data to delete function is when you want to track deletes in some other table and you need to throw in some information not accessible at database layer, only at business layer. Examples include application level user name or reason to delete. In this situation you need to construct entity with this values as original values. One way to do it:
var x = db.MyTable.Single(k => k.Id == id_to_delete);
x.UserName = logged_in_user;
x.ReasonForChange = some_reason;
// [...]
db.ObjectStateManager.ChangeObjectState(x, EntityState.Unchanged);
db.MyTable.DeleteObject(x);
db.SaveChanges();
Of course, better strategy might be to do it openly in business layer.
I don't understand your use case with rowversion/timestamp.
To avoid concurrency issues you pass original timestamp to modifying code.
That way it can be compared to current value in database to detect if record changed since you last read it.
Comparing it with new value makes little sense.
You usually use change markers that are automatically updated by database like rowversion/timestamp in SQL Server, rowversion in Oracle or xmin in PostgreSQL.
You don't change its value in your code.
Still, if you maintain row version manually, you need to provide:
a) new version to insert and update to be written, and
b) old version (read from database) to update and delete to check for concurrent changes.
You don't send new value to delete. You don't need to.
Also, when using stored procedures for modification, it's better to compute new version in the procedure and return it to application, not the other way around.
Hard to tell without seeing any code, but maybe when the postback occurs the page is being re-bound before your delete method is firing? On whatever method databinds the form controls (I assume it's OnLoad or OnInit), have you wrapped any databinding calls with if ( !this.IsPostBack ) { ... }?
Also I'm not sure if there's a reason why you're explicitly storing the concurrency flag in viewstate/session variables, but a better way to do it (imo) is to add the timestamp to the DataKeyNames property of the FormView/GridView (ie: <asp:FormView ID='blah' runat='server' DataKeyNames='Id, Timestamp'>.
This way you don't have to worry about manually storing or updating the timestamp. ;)

C# / Linq-to-sql - Lock datacontext.Table on insertonsubmit

I'm currently creating a method on my data access class that is going to insert an entity object to the database and I was expecting to get the latest inserted ID afterwards... and I've already done that but then I was wondering what would happend if the method somehow gets invoked twice at the same time, would it return the wrong ID?
So as a work around to that I decided to Lock the table on my datacontext:
lock(dataContext.Persons)
{
InsertOnSubmit(person);
dataContext.SubmitChanges();
}
but I do feel like this is inappropriate... I mean, the table isnt big and it wont take long to the datacontext to submit changes... So my question is, what kind of trouble would I run into by locking it like that?
PS: Let me know if my question was not clear enough and I'll edit it!
There is no need to lock your table.
LINQ-to-SQL will automatically populate your ID field with the identity from the database upon your call to .SubmitChanges() when you insert your person.
The caveat is that both your database and L2S entity must define your ID field as an identity. On your Person entity, you should have that field defined as the primary key, IsDbGenerated=true, UpdateCheck=never, and have the correct database type.
Once you submit, you should be able to simply retrieve the ID from your Person entity:
dataContext.Persons.InsertOnSubmit(person);
dataContext.SubmitChanges();
var id = person.ID; // now has the database generated identity.
Im not sure if this is part of your concerns, but if you use TransactionScope you can pass in a TransactionOption that will deal with multiple transactions.
Check out TransactionOption.Isolationlevel

WCF Data Services/Entity Framework : Logging client's username, Authentication, Authorization

I am using Entity Framework with WCF Data Services and I have the following table in my database :
Table Contract
Id (int)
Name (varchar)
byUser (varchar)
isDeleted (bit)
Entity Framework class
Id (int)
Name(string)
byUser(string)
isDeleted(boolean)
whenever the user is inserting/updating/deleting a contract(through a client app), I need to log who did the action.
so, I created Stored procedures for insert/update/delete that will receive the username from the client when an insertion/deletion/update is performed.
the issue is that the delete operation does not send over who is performing the operation :
var ctx = Context;
var contractToDelete = ctx.Contracts.Where(c => c.ContractId == 1).First();
contractToDelete.ByUser = username;
ctx.DeleteObject(contractToDelete);
ctx.SaveChanges();
at the server side, the byUser is always null.
Questions :
1) How do I make it so that the byUser parameter is sent to the server ?
2) Is there a better way to handle this kind of scenario ? (logging/authentication/authorization) with Entity Framework
It doesn't send null "always". It sends the old value always. That is some internal logic in entity framework. For each tracked object EF keeps both original and current values. When you are deleting object EF doesn't use current values - it uses original values (don't ask me why, simply this is how it works).
So you need to cheat EF:
var ctx = Context;
var contractToDelete = ctx.Contracts.Where(c => c.ContractId == 1).First();
contractToDelete.ByUser = username;
ctx.Contracts.ApplyOriginalValues(contractToDelete);
ctx.DeleteObject(contractToDelete);
ctx.SaveChanges();
Calling ApplyOriginalValues will force EF to override original values with values passed in parameter = you will override original values with current values.
In my opinion the better way is storing deleted records in separate table because it will avoid a lot of problems with passing isDeleted=false to every query where both eager and lazy loading will load deleted records as well. The only way to avoid problems with isDeleted is using conditional mapping but in such case you will not be able to load deleted records even if you want to unless you use stored procedures or direct SQL queries.
The way I managed this is, when my user logs in, I store basic information about them in the session. I then have a class that sits on top of my actions to context.
Whenever I commit back changes, I go through the same routine which checks what changed. I developed the ability to trigger actions based upon the entity being worked with (so I can keep an eye on something such as contracts). Then I have the user able to be logged.
[Edit]
This is tougher to clarify than I realised, but I'll try.
I'm creating a web application. Heavily using Ninject.
When the user logs in, I store their information in an IUserSession object (this is really held in Session, but a custom Ninject scope makes this neat for me and prevents me from having to expose my data layer to Web Session). This user session object contains username, user id etc.
I created a class that contains the context,and wraps all the SELECT,CREATE,DELETE and COMMIT calls. i.e. SELECT;
public IQueryable<TEntity> All<TEntity>( ) {
return Context.Set<TEntity>();
}
This class also has a Commit method, this is the call to SaveChanges.
Before calling SaveChanges, you have access to the changes in the form of Context.ChangeTracker.Entities
For each entity that has changed, you can test to see if it was added, deleted or modified.To get the type of the element being modified;
Type baseEntityType = ObjectContext.GetObjectType( entity.Entity.GetType( ) );
I do plan on writing up a tutorial soon, based upon my personal experience with doing this (not that that helps you right now).

Reading several tables from one single Entity Framework ExecuteStoreQuery request.

I have a library which uses EF4 for accessing a SQL Server data store. For different reasons, I have to use SQL Server specific syntax to read data from the store (for free text search), so I have to create the SQL code by hand and send it through the ExecuteStoreQuery method.
This works fine, except that the query uses joins to request several tables aside the main one (the main one being the one I specify as the target entity set when calling ExecuteStoreQuery), and EF never fills up the main entity's relationship properties with the other table's data.
Is there anything special to do to fill up these relationships? Using other EF methods or using special table names in the query or something?
Thanks for your help.
Executing direct SQL follows very simple rule: It uses column from the result set to fill the property with the same name in materialized entity. I think I read somewhere that this works only with the the main entity you materialize (entity type defined in ExecuteStoreQuery = no relations) but I can't find it now. I did several tests and it really doesn't populate any relation.
Ok so I'll write here what I ended up doing, which does not looks like a perfect solution, but it does not seem that there is any perfect solution in this case.
As Ladislav pointed out, the ExecuteStoreQuery (as well as the other "custom query" method, Translate) only maps the column of the entity you specify, leaving all the other columns aside. Therefore I had to load the dependencies separately, like this :
// Execute
IEnumerable<MainEntity> result = context.ExecuteStoreQuery<MainEntity>(strQuery, "MainEntities", MergeOption.AppendOnly, someParams).ToArray();
// Load relations, first method
foreach (MainEntity e in result)
{
if (!e.Relation1Reference.IsLoaded)
e.Relation1Reference.Load();
if (!e.Relation2Reference.IsLoaded)
e.Relation2Reference.Load();
// ...
}
// Load relations, second method
// The main entity contains a navigation property pointing
// to a record in the OtherEntity entity
foreach(OtherEntity e in context.OtherEntities)
context.OtherEntities.Attach(e);
There. I think these two techniques have to be chosen depending on the number and size of generated requests. The first technique will generate a one-record request for every required side record, but no unnessecary record will be loaded. The second technique uses less requests (one per table) but retrieves all the records so it uses more memory.

Categories

Resources