Migrating from LINQ to SQL to Entity Framework "Code First" - linq-to-sql

As I already have classes for my LINQ to SQL data access solution, what trouble might I run into if I wanted to migrate them over to EFCF instead? I'm hesistant to call this code first as the database does already exist. To be clear, the application is not yet in production so if EFCF wipes out the data it's no real loss.
Can I take a class such as the one that follows and simply use it in EFCF? Should I or must I remove the data annotation attributes?
What needs to change where I have EntityRef and EntitySet?
[Table]
public class PlanMember {
private EntityRef<SystemUser> _caseManager;
private EntityRef<PlanMemberStatus> _status;
public PlanMember() {
this.PlanMemberView = new Views.PlanMember();
}
[Column(
IsPrimaryKey = true,
IsDbGenerated = true,
AutoSync = AutoSync.OnInsert
)]
public Int64 ID { get; set; }
[Column]
public DateTime? BirthDate { get; set; }
[Column]
public String City { get; set; }
[Column]
public String FirstName { get; set; }
[Association(ThisKey = "CaseManagerID", Storage = "_caseManager")]
public SystemUser CaseManager {
get { return (this._caseManager.Entity); }
set { this._caseManager.Entity = value; }
}
[Column]
public String CaseManagerID { get; set; }
[Column]
public Boolean IsActive { get; set; }
public Boolean IsEligible {
get { return (this.PlanMemberView.IsEligible); }
}
[Column]
public String LastName { get; set; }
[Column]
public String MedicalRecord { get; set; }
[Column]
public String MemberNumber { get; set; }
[Column(Name = "PCPFullName")]
public String PrimaryCarePhysicianFullName { get; set; }
[Association(OtherKey = "PlanMemberID")]
public Views.PlanMember PlanMemberView { get; set; }
[Column]
public Int32 PostalCode { get; set; }
[Column]
public String Sex { get; set; }
[Column]
public String State { get; set; }
[Association(ThisKey = "StatusID", Storage = "_status")]
public PlanMemberStatus Status {
get { return (this._status.Entity); }
set { this._status.Entity = value; }
}
[Column]
public Int32 StatusID { get; set; }
}

We migrated an application from Linq to Sql to EF POCO generation but haven't tried code first as it wasn't baked at the time. Was really not horribly difficult. The main pain point in our case was the following differences:
Linq to Sql handles many to many relationships using a separate "bridge" object, EF treats those relationships as collections of various sorts. This changes lots of semantics and can cause lots of code to change, especially if you let entities creep into the UI.
Another pain point was nullable and non-nullable relationships. Linq to Sql was a bit more forgiving here, but for EF to play well we needed to allow nullable columns some places we traditionally had not.
Linq to Sql and EF data mapping sometimes have different ideas about what CLR types to map to. Xml columns were our major pain point but you might not have any of those.
Big trick/nightmare was how to get rid of the l2s bits without breaking everything horribly as linq to sql generates your entities.
This is not something I would try without a pretty effective set of unit tests to give you an automated basis to give you pretty regular temperature readings. Our other godsend was we had a pretty solid Repository pattern implementation -- nothing was talking directly to the EF/Linq2Sql bits but two classes implementing IRepository. Basically, this is a great test for how disciplined you were in implementing your architecture. Also, it is an occasion when you realize that resharper is worth every cent.
To answer your one direct question, I don't think the attributes will necessarily matter but I would remove them so as not to have any potential confusion and/or namespace collisions.

Assuming your classes are named the same as your database tables, and the properties of your classes match the database column names, you should be able to delete all the attributes and use these same classes as your EF code-first model (I don't think you have to delete the attributes, but unless you plan to continue using them in a Linq2Sql model, there's no reason to keep them, and since some things will probably change in the migration, it would probably be best to delete them since your new entities may not still be able to work in Linq2Sql). If your classes don't match your database schema, Scott Guthrie has a blog post about Entity Framework 4 "Code-First": Custom Database Schema Mapping.
What needs to change where I have EntityRef and EntitySet?
A relation defined as EntityRef<OtherEntity> can be replaced with a property of just type OtherEntity, and an EntitySet<OtherEntity> can become an ICollection<OtherEntity> or anything that implements ICollection<T> such as an IDbSet<OtherEntity> (I believe a DbSet<T> is what you would get if you were generating the model from your existing database).

Related

Enity Framework Core: Handling large number of enum-like fields

I am currently facing the following problem:
I have a model class LargeDataClass with many fields (200+).
Many of these fields (~50-80) are enum-like (i.e. they can be filled out with certain sets of options in the UI).
Now my approach was to model these as enum classes, like
[Table("tbl_enum_one")]
class EnumOne {
public int ID { get; set; }
public string Name { get; set; }
}
[Table("tbl_large_dataclass")]
class LargeDataClass {
public EnumOne EnumOne { get; set; }
public int EnumOneId { get; set; }
//...
}
This has the major advantage of being easily extendable (to add a dropdown option in the UI, just add a row to the table).
Now I am facing some concerns/problems:
When I fetch my model class LargeDataClass from the DB with all its enum fields included, there will be a lot of joins (as I stated above, there are like 50 to 80 of these fields). I am worried that will have a big impact on query performance. Plus create/update/delete might be quite slow due to the large number of indexes to be updated.
MySQL won't even let me create a table tbl_large_dataclass with that many FKs (too many indexes on a single table).
So now I am considering two (in my view really unfortunate) options:
Using regular enums, so no enum classes with their own tables, storing them as simple int/string fields in the DB. This would cause no performance concerns at all, but unfortunately, the 'live' extendability is quite important, so this option would only be the last resort.
Using the Enum classes, but having just the ID of the enum in the LargeDataClass, so kind of keeping the fact that this is a foreign key secret from the DB. If I wanted to display a LargeDataClass object somewhere, I would have to separately fetch the enum classes. Plus I would have to make extra sure everywhere that I only use Ids that are really present in the enum table.
I am really unsure what would be the best approach here.
Database is not an object store and you have to design it accordingly. I have changed you schema and only two tables are needed for storing dropdown values.
[Table("tbl_enum_type")]
public class EnumType {
public int ID { get; set; } // PK
public string Name { get; set; }
}
// PK (EnumTypeId, Id) - reusing the same index for dropdown generation
[Table("tbl_enum_value")]
public class EnumValue {
public int ID { get; set; }
public string Name { get; set; }
public int Order { get; set; } // for dropdown ordering
public int EnumTypeId { get; set; }
public EnumType EnumType { get; set; }
}
// store only ID's, no FK
[Table("tbl_large_dataclass")]
public class LargeDataClass {
public int EnumOneId { get; set; } // EnumTypeId 1
public int EnumSecondId { get; set; } // EnumTypeId 2
//...
}
For generating dropdowns, you have to cache EnumType and EnumValue tables in memory in useful structure.
Override method SaveChanges/SaveChangesAsync and check saved Id's according to cached data.
It will not help if your database is changed via SQL, but here we have trade-off between performance and consistency. Probably good trigger may help here.
UPDATE:
Consider to restructure LargeDataClass to two tables
[Table("tbl_option_bag")]
public class OptionBag {
public int Id { get; set; }
public ICollection<Option> Options { get; set; }
}
[Table("tbl_options")]
public class Option {
public int Id { get; set; }
public int OptionBagId {get; set; }
public int EnumTypeId { get; set; }
public int EnumId { get; set; }
//...
}
Here you can use FK and DTO can be generated on selecting Options navigation property.

Entity Framework 4.1 Problems Updating Foreign Key Properties

I am working on an application using Entity Framework 4.1 with DbContext API, in a disconnected environment. I have two basic entities, Person and Degree. Degree has a non-mandatory one-to-many relationship to Person.
The issue is occurring when I update the DegreeId property on the Person entity to a different value. When I save the changes, EF generates an Update statement on the actual Degree table. This in turn causes a concurrency error violation when two or more users are using the application. I was able to find the issue while using SQL Profiler. I’ve tried several configuration variations using the Fluent API, but nothing seems to suppress the additional Update statement on the Degree table.
Here are my entities:
public partial class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public Nullable<int> DegreeId { get; set; }
public Degree Degree { get; set; }
}
public partial class Degree
{
public int DegreeId { get; set; }
public string Name { get; set; }
}
In my Repository class, I am loading the Person object graph as such:
public override Person GetById(int id)
{
return DataContext.People
.Include(d => d.Degree)
.FirstOrDefault(x => x.PersonId == id);
}
In my Service layer, I am getting a person record, and then updating the DegreeId property to a specific value. Note: UnitOfWork.Commit method exposes SaveChanges on DbContext.
using (var unitOfWork = IoC.Resolve<IUnitOfWork>())
{
var personRepository = new PersonRepository(unitOfWork);
var person = personRepository.GetById(240);
person.DegreeId = 1;
personRepository.Update(person);
unitOfWork.Commit();
}
My repository update method attaches the person entity and marks the entity state as modified:
var state = DataContext.Entry(entity).State;
dbSet.Attach(entity);
DataContext.Entry(entity).State = EntityState.Modified;
Here is the SQL statement found in the Profiler session:
exec sp_executesql N'declare #p int
update [Client].[Degree]
set #p = 0
where (([DegreeId] = #0) and ([RowVersion] = #1))
select [RowVersion]
from [Client].[Degree]
where ##ROWCOUNT > 0 and [DegreeId] = #0',N'#0 int,
#1 binary(8)',#0=1,#1=0x0000000000004469
Does anyone know how to stop EF from sending this update statement to SQL Server? Is there something apparent in my entity configuration that causes EF to assume the Degree is also affected?
Thank you.
I was able to find the cause of this issue and prevent it from occurring, but I cannot really explain why it was occurring.
My tables include a TimeStamp column and a corresponding property in the base class for my entities.
I did not show the base class in my original question because it only includes the RowVersion and other audit properties, which I assumed were irrelevant.
One would think I would've learned by know not assume anything about Entity Framework.
Here is my base class definition for the Degree entity:
public abstract class EntityBase : ValidableObject, IEntityBase
{
public virtual byte[] RowVersion { get; protected set; }
public virtual DateTime? CreateDate { get; set; }
public virtual string CreateUser { get; set; }
public virtual DateTime? ModifyDate { get; set; }
public virtual string ModifyUser { get; set; }
}
Here is my context model configuration for the Degree entity:
internal class DegreeConfiguration : EntityTypeConfiguration<Degree>
{
internal DegreeConfiguration()
: base()
{
ToTable("Degree", "dbo");
Property(x => x.RowVersion).IsRowVersion();
}
}
Because of my application requirements, I must load the Person entity using the Include method to eagerly load the Degree entity so the object graph is
fully populated when the consumer requests the entity.
return ctx.People.Include(p => p.Degree).Where(x => x.PersonId == id).First();
When the DegreeId property of the Person object is modified and attached to the Context, the following Update statement is generated
upon calling SaveChanges():
exec sp_executesql N'declare #p int
update [dbo].[Degree]
set #p = 0
where (([DegreeId] = #0) and ([RowVersion] = #1))
select [RowVersion]
from [dbo].[Degree]
where ##ROWCOUNT > 0 and [DegreeId] = #0',N'#0 int,
#1 binary(8)',#0=2,#1=0x00000000000007DF
This is occurring even though I am not knowingly updating the Degree entity and causes havoc when two or more users using the application simultaneously.
To suppress the Update statement from being generated on the Degree navigation property, I commented out the concurrency check on the model configuration as such:
internal class DegreeConfiguration : EntityTypeConfiguration<Degree>
{
internal DegreeConfiguration()
: base()
{
ToTable("Degree", "dbo");
//Property(x => x.RowVersion).IsRowVersion();
}
}
Upon re-executing the process, EF no longer generates the problematic Update statement.
I've done a considerable number of searches both on MS site for EF 4.1, as well as general Google searches. I cannot come up with any concrete explanations.
Thank you.

EF - Saving a new entity with linked existing entities creating duplicates

public class Car {
public string SomeProperty { get; set; }
public Manufacturer Manufacturer { get; set; }
public IList<Color> Colors { get; set; }
}
public class Manufacturer {
public int Id { get; set; }
public string Name { get; set; }
}
public class Color {
public int Id { get; set; }
public string Name { get; set; }
}
I already have tables full of Colors and Manufacturers. When I create a new car I want to be able to assign it a Color and Manufacturer bound from .net MVC.
When I save my new car with
context.Cars.Add(car);
A new Car is created (great) but a new Color and Manufacturer are also created even though these objects already had an Id and Name set that matched the content in the database.
The two solutions I see are to either write a custom save method for car, and tell the context that the Manufacturer and Color are Unchanged.
context.Cars.Add(car);
context.Entry(car.Manufacturer).State = EntityState.Unchanged;
foreach (Color color in car.Colors)
context.Entry(car.Color).State = EntityState.Unchanged;
Alternatively, to load the Manufacturer and Color from EF and then link them to the Car, instead of using the MVC bound objects.
car.Manufacturer = carRepository.GetManufacturer(car.Manufacturer.Id);
car.Colors = carRepository.GetColorsById(car.Colors);
I am not thrilled by either solution as this example is very trivial, but my real cases are far more complicated. I don't really want to have to fiddle around with EF in detail for each object I save. I have lots of complex object graphs to save and this seems very error prone.
Is there a way of making EF behave more like NHibernate, whereby you can give it something with an ID already assigned and it will assume without your intervention that it already exists?
Edit - question clarified to show collection of existing entities as well as many-to-one relationships.
Unfortunately, EF does not have anything like session.Load in NHibernate that allows you to get a proxy from an id.
The usual way to deal with this in EF is create a separate FK field containing the scalar value that corresponds to the reference. For example:
public virtual Manufacturer Manufacturer { get; set; }
public int ManufacturerId { get; set; }
Then you only have to set ManufacturerId and it will be saved correctly.
(So much for "POCO" and "code first". Pffffff)
You can define scalar properties in your entities and bind the values to them instead. Eg add
ManufacturerId and ColorId
public class Car {
public string SomeProperty { get; set; }
public int? ManufacturerId { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
public int? ColorId { get; set; }
public virtual Color Color { get; set; }
}
Then set those scalar properties when you assign (eg through a DropDownList)
This way you can avoid loading many related entities to populate the entity.

Can you help me understand this C# code?

I'm reading Pro ASP.Net MVC2 and I've gotten to a point where nothing is explained well enough. For example, the following tells me to create this C# code manually:
Implementing the Auctions Domain Model
With LINQ to SQL, you can set up mappings between C# classes and an implied database schema either
by decorating the classes with special attributes or by writing an XML configuration file. The XML option
has the advantage that persistence artifacts are totally removed from your domain classes,4 but the
disadvantage that it’s not so obvious at first glance. For simplicity, I’ll compromise here and use
attributes.
Here are the Auctions domain model classes now fully marked up for LINQ to SQL:5
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq.Mapping;
using System.Data.Linq;
[Table(Name="Members")]
public class Member
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
internal int MemberID { get; set; }
[Column]
public string LoginName { get; set; }
[Column]
public int ReputationPoints { get; set; }
}
[Table(Name = "Items")]
public class Item
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public int ItemID { get; internal set; }
[Column]
public string Title { get; set; }
[Column]
public string Description { get; set; }
[Column]
public DateTime AuctionEndDate { get; set; }
[Association(OtherKey = "ItemID")]
private EntitySet<Bid> _bids = new EntitySet<Bid>();
public IList<Bid> Bids { get { return _bids.ToList().AsReadOnly(); } }
}
Where exactly do I have to write this in? Or is he just displaying generated code by the Linq-to-sql DBML?
That's not generated code. That's how you use Linq mappings to map your classes to your database.
You just write it in a CS file. It can go anywhere, but if you're using ASP.NET MVC you'd usually put it in the Models folder.
See this: http://msdn.microsoft.com/en-us/library/bb386971.aspx

Applying Domain Model on top of Linq2Sql entities

I am trying to practice the model first approach and I am putting together a domain model. My requirement is pretty simple: UserSession can have multiple ShoppingCartItems.
I should start off by saying that I am going to apply the domain model interfaces to Linq2Sql generated entities (using partial classes). My requirement translates into three database tables (UserSession, Product, ShoppingCartItem where ProductId and UserSessionId are foreign keys in the ShoppingCartItem table). Linq2Sql generates these entities for me. I know I shouldn't even be dealing with the database at this point but I think it is important to mention.
The aggregate root is UserSession as a ShoppingCartItem can not exist without a UserSession but I am unclear on the rest. What about Product? It is defiently an entity but should it be associated to ShoppingCartItem?
Here are a few suggestion (they might all be incorrect implementations):
public interface IUserSession {
public Guid Id { get; set; }
public IList<IShoppingCartItem> ShoppingCartItems{ get; set; }
}
public interface IShoppingCartItem {
public Guid UserSessionId { get; set; }
public int ProductId { get; set; }
}
Another one would be:
public interface IUserSession {
public Guid Id { get; set; }
public IList<IShoppingCartItem> ShoppingCartItems{ get; set; }
}
public interface IShoppingCartItem {
public Guid UserSessionId { get; set; }
public IProduct Product { get; set; }
}
A third one is:
public interface IUserSession {
public Guid Id { get; set; }
public IList<IShoppingCartItemColletion> ShoppingCartItems{ get; set; }
}
public interface IShoppingCartItemColletion {
public IUserSession UserSession { get; set; }
public IProduct Product { get; set; }
}
public interface IProduct {
public int ProductId { get; set; }
}
I have a feeling my mind is too tightly coupled with database models and tables which is making this hard to grasp. Anyone care to decouple?
Looks like you are on the right track. Half of the whole "doing DDD right" is having the right base classes. Have a look at this great DDD applied to C# resource:
http://dddpds.codeplex.com/
The source code is available and is very readable.
So, with regards to having ID in the model. The ID is a database thing and the usual approach is to keep all persistence out of the Model and restrict the model to the business logic. However, one normally makes an exception for the identifier and buries it in the Model base class like so:
public class ModelBase {
protected readonly object m_Key;
public ModelBase(object key) {
m_Key = key;
}
}
This key is used by your persistence layer to talk to the database and is opaque. It's considered quite OK to downcast the key to the required type, because you know what it is.
Also, the Domain Objects are pretty much on the bottom of your architecture stack (just above the Infrastructure layer). This means that you can make them concrete classes. You will not have multiple implementations of the domain models, so the interfaces are unnecessary, which is what Domain Driven Design is about - Domain first.
public Class UserSession : ModelBase {
public UserSession(Guid Id):base(Id) {}
public Guid Id { get{ return m_Key as Guid;} }
public IList<ShoppingCartItem> ShoppingCartItems{ get; set; }
}
public class ShoppingCartItem : ModelBase {
public ShoppingCartItem ():base(null) {}
public UserSession UserSession { get; set; }
public Product Product { get; set; }
}
Typical shopping cart or customer-order examples prefer making UserSession (or Order) the root of aggregate. Individual items should be children of this session/order. It is up you whether individual items in the cart should have a meaningful id. I would prefer no, since 5 widgets in the cart are indistinguishable from another 5 widgets. Hence, I would model cart items as a collection of value objects.
Common problem with shopping cart items is whether they should include price, or not. if you include price, you will have your cart independent from changes of product price. It is very desirable if you want to store you cart for historical reasons since it is valuable to know how much items in the cart cost according to price when they were bought, not according to current.
Product should form definitively an aggregate by itself. Period.
Now, I don't know if all of this is easily implementable in LINQ to SQL, but you can try.