Linq To SQL context update - persist attibute parameter - c#

Whenever a Linq data context is updated, all manually set attribute parameters are lost. I wonder if there is a way to persist them somehow? For instance, we need to persist an Auto Generated Value property represented by a IsDbGenerated attribute parameter of a ColumnAttribute, which is used, for example, for auto incrementing ID column.
Thanks in advance.

You can't manually edit the designer.cs file and expect your changes to persist after you have updated something using the designer, however you can control the values of all of the auto generated parameters via the designer and these changes are persisted so long as you don't delete and re add the table/class.
If you want to add custom attributes unrelated to LinqToSql you can take advantage of the fact that the LinqToSql classes are all partial classes. Move the properties into another file that continues the partial class. This will then get left alone when you update the designer file. However you will have to manage any database changes to the that need to be reflected on these properties manually and not through the designer.

Related

Can I tell linq 2 SQL not to update certain columns after attachment or use of UpdateModel?

Let's assume I have the following situation, the update method in my service accepts a model (the one that is going to be updated) as an input parameter. The model can be unattached (in which case attach method is called before submitting changes) or attached (in which case we just submit changes). Edit actions just call this update method in my service. Now let's assume I cannot change the code in those actions (the code that produces the model to be updated). Can I still somehow prevent certain columns from updating from within the update method. Note that I might want to set those columns using linq to SQL, but only during insert method.
I'm quite sure I'm trying something unconventional here, but it might help me write some easy to reuse code. If it cannot be done, then I'll solve it differently, but it never hurts to try something new.
The Attach method does provide an override to accept both a modified and original entity.
Attach Modified Entity on Data Context
When using this the internal change tracker will figure out which columns have been updated and will only update those ones on the datasource which have changed, rather than updating all columns.
Alternatively if you want more explicit control over which properties are updated, you can reattach your entity as unmodified in its original state:
Attach Modified/Unmodified Entity on Data Context
This will hook up the internal change tracker to the PropertyChanging events on the entity so it can be tracked. You would then simply change the values of the properties on that entity in the Update method on your Service.
void Update(MyModel model)
{
using (MyContext ctx = new MyContext())
{
ctx.DeferredLoadingEnabled = false;
ctx.MyEntities.Attach(model.OriginalEntity);
model.OriginalEntity.Value = model.ModifiedEntity.Value;
ctx.SubmitChanges();
}
}
The pitfall of these approaches means you must maintain both the original and modified entities in your model, but could be set when your entities are loaded - a simple shallow copy of the object should do the trick by deriving from ICloneable in a partial class for each entity.

Add an extra column to my model in an .edmx file

I want to add an extra column, similar to a join to my model based on the ID. Is this possible?
For example:
ProductsModel
ID
DeliveryID
DeliveryModel
DeliveryID
DeliveryDescription
What I'd like to do is add the DeliveryDescription column to my ProductsModel in my .edmx file. I know its possible to add 3 property types (scalar, navigation, complex) are one of these the solution?
No. Default entities must exactly match your tables. There are situations where this is not the true but all involve advanced mapping features like splitting or inheritance. By looking at your tables neither of this is case.
What you are trying to do is equivalent to database view. It is possible in EF by either using QueryView or DefiningQuery. Both will result in new read-only entity type. To use these advanced features you must manually edit EDMX file (and in case of DefiningQuery you cannot use update from database any more because it would delete your changes).
You most probably need this for some data presentation so instead of modifying your mapped entities create a new class outside of EF just for presentation and fill it from entities.

Disabling Entity Framework's default value generation (Code First)

I have a column in the database that cannot be null, and I want to set it to have a default value in the database . The problem is that entity framework seems to create a default value itself (for example, int => 0), and completely ignores the default value constraint in the database.
Is there any way to disable this default valuing of entity framework?
I have found that you can decorate your fields with the following attribute.
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
Natively, Entity framework do not allows this. You have to do some code to it. This answer from another site seems to had solved the problem for many people.
He "hacks" it (as he told) by doing something like that:
public partial class YourEntityClass {
public YourEntityClass() {
this.PropertyNameWithDefaultValue = default(int);
}
}
Note 1 : Someone mention that it may not work in EF4
Personal note : Sorry for my english, I usually speak French.
Sometimes we need to do manually what EF doesn't do automatically for us.
In case using EF 4.1 "Code First", I usually create a separated class DbInitializer derived from IDatabaseInitializer, and in the implementation of the InitializeDatabase method, just call the
context.Database.ExecuteSqlCommand("ALTER TABLE TABLENAME ... ");
Now at the static constructor of the class derived from DbContext, just call the initializer:
Database.SetInitializer(new DbInitializer());
In this way, it's possible to specify any database DML/DDL commands to alter tables/columns just to make sure the DB is like we want.
"Computed" fields in EF are not the same as fields with default values in SQL. A computed field is one that is computed on the server and shouldn't be altered when an object is submitted. If you put a Computed tag on a field, you will get the default when you first create the object, but then you will not be able to change that field later on. So, if you get an entity from the DB make a change to a computed field and then call "saveChanges()" on your entity context, the field will not be altered in the DB.
Better to use EF defaults by setting the Default Value for the attribute in the EDMX editor.
It's a pain in the butt that the EDMX updater can't read the field defaults when there is a one to one mapping between the entity field and the database field.
You can update the EDMX model to change the default value for any column via the Properties window. However, Entity Framework doesn't seem to pickup DEFAULT constraints automatically. Not sure if there is a way to make it do that.

default vs custom using entity framework

I've got a table of default templates. It's global to all users. If a user has no custom template, I want to pull the default. If a user decides to customize the template it should be saved in a customtemplates table - as opposed to the globaltempaltes table.
the custom table has all the globaltemplates fields plus a userid and an id relating to which global it is replacing.
To flesh this out a bit more, lets say there are 3 templates, and a user wants to customize template 2 only. I would normaly pull the whole globaltemplates table and whatever relates to the user in the customtemplates table. Then, in the class property I'd do something in the get like this:
MyTemplateA
get { return customtemplates.A ?? globaltemplates.A; }
Can I do this using straight ef4/linq without poco?
Would a partial class with some additional properties like the get above work?
Since i'm always editing only the customtemplates table (add/edit/delete) it doesn't matter which version of the template I pull. I guess it could get hairy figuring out if it's an insert or an update.
In my opinion it will not work as you expect because EF closely relates entity to table. You cannot have single entity mapped to two tables except very special situations like splitting or inheritance.
So if you have Template entity it can be mapped only to single table but you have two. What you can do is to use TPC inheritance where Template will be a base entity mapped to GlobalTemplates table and UserTemplate will be derived entity mapped to UserTemplates table. TPC (table per concrete type) is type of inheritance where table for derived entity contains all columns from table for parent entity.
But inheritance still has a few problems for your scenario:
Template is editable - if you want to have it read only you must correctly handle it in your application logic. Any changes to attached Template instance will be saved when you call SaveChanges on the context.
When you load Template you cannot directly convert it to UserTemplate to make it user specific. You must create new instance of UserTemplate and copy properties from Template to the newly created instance.

LinqToSQL and auditing changed fields

Here's another one of these LinqToSQL questions where I'm sure I must have missed the boat somewhere, because the behavior of the O/R Designer is very puzzling to me...
I have a base class for my LinqToSQL tables, which I called LinqedTable. I've successfully used reflection to get hold of all the properties of the descendant classes and do other standard stuff.
Now I want to have some automatic auditing of my tables, so that whenever a LinqedTable record is inserted or deleted, or a field value changes, I will insert a record into an audit table, detailing the change type, the field name, and its value pre- and post-save.
I thought I would be able to do it using the PropertyChanging event, keeping track of all the changed properties before a save, then clearing the collection of changes after each SubmitChanges() call. But - the generated code from the O/R designer, for some bizarre reason, doesn't give you the property name in the PropertyChanging event - it sends an empty string! (WHY?!) It does send the property name in the PropertyChanged event, but that's already too late for me to get the original value.
I thought to grab all the original values of all properties using the OnLoaded() partial method - but that is private by definition, and I need access to that method in the base class. Even if I used reflection to get hold of that method, that would mean I would have to implement the other half of the partial method for every one of my tables, which kinda defeats the purpose of having inheritance!
I also can't find any suitable method in the DataContext to use or override.
So what would you recommend to get this audit functionality working?
You can use GetChangeSet on the DataContext to retrieve a list of updates, inserts and deletes that have occurred on all tables within a context. You can use ITable.GetOriginalEntityState to retrieve the original values of a changed entity. However, when you retrieve the original values of a deleted or updated record, the associations will not be available so you will have to rely on foreign key values only in that area if you need to process related entities. You can Use ITable.GetModifiedMembers to help retrieve only values that have changed.
Forgive me for perhaps a stupid answer, but how about doing the audit directly in the SQL Server using triggers (if you are in SQL Server 2005 or 2008 standard) or using the change tracking facilities in SQL server 2008 Enterprise?

Categories

Resources