How can i create a composite primary key in parent using fields in a valueobject ?
The valueobject will not have an own table in the database, i want these two props to be inserted into the parents table.
ie.
Entities
public class Parent
{
public string Name { get;set; }
public MyValueObject MyValueObj { get;set; }
}
public class MyValueObject
{
public int Id { get;set; }
public int SSN { get;set; }
}
DbContext for parent
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>().Property(new { p.MyValueObj.Id, p.MyValueObj.SSN}).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
I want the Parent table to look like this:
Composite PK
-----------
Id SSN Name
1 000000 Mikael
If you can use inheritance then it should look like this:
public class Parent : MyValueObject
{
public string Name { get;set; }
}
public class MyValueObject
{
public int Id { get;set; }
public int SSN { get;set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>().Property(new { p.Id, p.SSN}).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
The reason why your implementation won't work is pretty simple - Entity Framework just can't transform your complex object (which is set as property) to SQL field, so it will try to find it as a referenced object in other table. In the code I've provided you don't have any complex objects as a property, so EF will easily map all properties to SQL columns.
UPDATE
Actually, I did some more investigations and found an article stating that you can use complex types. I have never used this (and even seen) before, so can't describe you all sides of this question, but what I see from article is that this complex property can't be optional, so you will need always initialize that. Also I can only suppose, but probably you don't even need to mark all fields of that complex type as primary key, so you should have something just like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Parent>().Property(p => p.MyValueObj).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
base.OnModelCreating(modelBuilder);
}
Not sure if that will work, just give it a try :)
Related
I need to create a unique constraint on multiple fields, and those fields are ValueObjects.
Let's say I have this
public class MyEntity
{
public EntityCode Code {get;set;}
public SecondaryCode Second {get;set;}
}
public class EntityCode : ValueObject<string>
{
public string Value {get;set;}
public string Description {get;set;}
}
public class SecondaryCode: ValueObject<string>
{
public string Value {get;set;}
public string Description {get;set;}
}
I can create a unique constraint like this
public class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
...
builder.OwnsOne(p => p.Code)
.HasIndex(p => p.Value)
.IsUnique()
...
}
But I would like a composite key and I can't figure out how to do this with value object.
Take a look at this sample, it is not working as I expected
builder.OwnsOne(p => p.Code);
builder.OwnsOne(p => p.Second);
builder
.HasIndex(p => new { p.Code.Value, p.Seconde.Value })
.IsUnique()
Any help would be appreciated
A key serves as a unique identifier for each entity instance. Most entities in EF have a single key, which maps to the concept of a primary key in relational databases. You can also configure multiple properties to be the key of an entity - this is known as a composite key.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
builder.Entity<MyEntity>()
.HasKey(p => new { p.Code.Value, p.Seconde.Value });
}
Composite keys can only be configured using the Fluent API, conventions will never set up a composite key, and you can not use Data Annotations to configure one.
To create this composite primary key with these two columns, override DbContext.OnModelCreating(). This method is called when the model for a derived context has been initialized, but before the model has been locked down and used to initialize the context.
public class MyDbContext : DbContext
{
// Normal DbContext stuff here
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
builder.Entity<MyEntity>()
.HasKey(p => new { p.Code.Value, p.Seconde.AnotherValue });
}
}
after that generate the migration and update database.
EF by default name my FKs as EntityName_id and I would like it to be named id_EntityName. How can I do that?
Edit1:
There are over 700 FKs here... automate this would be a lot faster I belive... Also intend to use the same answer to normalize composite PKs...
MSDN has an example of creating a custom ForeignKeyNamingConvention. You could modify this example to name the Foreign Keys according to your convention.
I haven't tested this, but here's some rough code that you might be able to build on:
public class ForeignKeyNamingConvention : IStoreModelConvention<AssociationType>
{
public void Apply(AssociationType association, DbModel model)
{
if (association.IsForeignKey)
{
var constraint = association.Constraint;
for (int i = 0; i < constraint.ToProperties.Count; ++i)
{
int underscoreIndex = constraint.ToProperties[i].Name.IndexOf('_');
if (underscoreIndex > 0)
{
// change from EntityName_Id to id_EntityName
constraint.ToProperties[i].Name = "id_" + constraint.ToProperties[i].Name.Remove(underscoreIndex);
}
}
}
}
}
You can then register your custom convention in your DbContext's OnModelCreating() method like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add<ForeignKeyNamingConvention>();
}
I think that the best way is to use fluent mapping, for instance
.Map(m => m.MapKey("id_EntityName")
You can do this through setting up the mappings for your entities.
public class User
{
public int Id {get;set;}
public virtual Address Address {get;set;}
}
public class Address
{
public int Id {get;set;}
//Some other properties
}
public class UserMapping: EntityTypeConfiguration<User>
{
public UserMapping()
{
HasOptional(u => u.Address).WithMany()
.Map(m => m.MapKey("Id_Address"));
}
}
//Override the OnModelCreating method in the DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuild.Configurations.Add(new UserMapping());
}
I have 2 table which I'm trying to access in MVC, one called Employees and one called Accountable. This is my code: -
public class dbEntity: DbContext
{
public dbEntity(): base("name=dbEntity") {}
public DbSet<Accountable> Accountable { get; set; }
public DbSet<Employees> Employees { get; set; }
}
The problem is the code complains that it can't find the table 'Accountables', I know I can add this line: -
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); }
But then the code complains that it can't find 'Employee'. At the moment it is not practical to rename the tables, is there another way around it?
Thanks
Add a data annotation of your table's name in the database to your context class.
[Table("TableName")]
I'm trying to implement a TPC inheritance model in EF 4.3 CodeFirst for an existing Oracle database (over which I have no control). I have several sub-types that each map to its own table. Unfortunately, some of the key columns are of datatype number(18,0) instead of integer. EF seems to hate me now.
Here's my base class:
public abstract class Vehicle
{
public virtual int Id { get; set;}
public virtual string Color { get; set; }
//more properties
}
Here are some example sub-types:
public class Car : Vehicle
{
//more properties
}
public class Truck : Vehicle
{
//more properties
}
public class Motorcycle : Vehicle
{
//more properties
}
And here's my DbContet:
public class VehicleDataContext : DbContext
{
public DbSet<Vehicle> Vehicles { get; set; }
public DbSet<Car> Cars { get; set; }
public DbSet<Truck> Trucks { get; set; }
public DbSet<Motorcycle> Motorcycles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Vehicle>().HasKey(x => x.Id);
modelBuilder.Entity<Car>().Map(m => m.MapInheritedProperties());
modelBuilder.Entity<Car>().Property(x => x.Id).HasColumnType("decimal");
modelBuilder.Entity<Truck>().Map(m => m.MapInheritedProperties());
modelBuilder.Entity<Truck>().Property(x => x.Id).HasColumnType("int");
modelBuilder.Entity<Motorcycle>().Map(m => m.MapInheritedProperties());
modelBuilder.Entity<Motorcycle>().Property(x => x.Id).HasColumnType("decimal");
base.OnModelCreating(modelBuilder);
}
}
So, I already know to MapInheritedProperties so that all the properties of the base and sub-type are mapped to one table. I'm assuming that I have to tell the base that it HasKey so that EF doesn't complain that my DbSet<Vehicle> doesn't have a key mapped. I'd like to be able to assume that I can "tell" each entity how to map its own key's column type like I've done above. But I think that's not quite it.
Here's a test that fails:
[TestFixture]
public class when_retrieving_all_vehicles
{
[Test]
public void it_should_return_a_list_of_vehicles_regardless_of_type()
{
var dc = new VehicleDataContext();
var vehicles = dc.Vehicles.ToList(); //throws exception here
Assert.Greater(vehicles.Count, 0);
}
}
The exception thrown is:
The conceptual side property 'Id' has already been mapped to a storage
property with type 'decimal'. If the conceptual side property is
mapped to multiple properties in the storage model, make sure that all
the properties in the storage model have the same type.
As mentioned above, I have no control over the database and it's types. It's silly that the key types are mixed, but "it is what it is".
How can I get around this?
You cannot achieve it through mapping. This is limitation of EF code first. You can map each property (including the key) in inheritance structure only once. Because of that you can have it either integer or decimal in all entities in the inheritance tree but you cannot mix it.
Btw. what happens if you try to use int or decimal for the whole inheritance tree? Does it fail for loading or persisting entity? If not you can simply use the one (probably decimal if it can use whole its range) for all entities.
How do I make non persisted properties using codefirst EF4?
MS says there is a StoreIgnore Attribute, but I cannot find it.
http://blogs.msdn.com/b/efdesign/archive/2010/03/30/data-annotations-in-the-entity-framework-and-code-first.aspx
Is there a way to set this up using EntityConfiguration?
In EF Code-First CTP5, you can use the [NotMapped] annotation.
using System.ComponentModel.DataAnnotations;
public class Song
{
public int Id { get; set; }
public string Title { get; set; }
[NotMapped]
public int Track { get; set; }
Currently, I know of two ways to do it.
Add the 'dynamic' keyword to the property, which stops the mapper persisting it:
private Gender gender;
public dynamic Gender
{
get { return gender; }
set { gender = value; }
}
Override OnModelCreating in DBContext and remap the whole type, omitting the properties you don't want to persist:
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Person>().MapSingleType(p => new { p.FirstName, ... });
}
Using method 2, if the EF team introduce Ignore, you will be able to easily change the code to:
modelBuilder.Entity<Person>().Property(p => p.IgnoreThis).Ignore();
If you don't want to use Annotations, you can use the Fluent API. Override the OnModelCreating and use DbModelBuilder's Ignore() method. Supposing you have a 'Song' entity:
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Song>().Ignore(p => p.PropToIgnore);
}
}
You can also use EntityTypeConfiguration to move configurations to separate classes for better manageability:
public class MyContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SongConfiguration());
}
}
public class SongConfiguration : EntityTypeConfiguration<Song>
{
public SongConfiguration()
{
Ignore(p => p.PropToIgnore);
}
}
I'm not sure if this is available yet.
On this MSDN page the Ignore Attribute and API are described but below, in the comments, somebody writes on 4 june 2010:
You will be able to ignore properties in the next Code First release,
Add
using System.ComponentModel.DataAnnotations.Schema
to the model class. (Must include "SCHEMA")
Add [NotMapped] data annotation to the field(s) you want to keep from persisting (ie. not save to database).
This will prevent them from being added as a column to the table in the db.
Please note - previous answers may have included these bits, but they did not have the full "using" clause. They merely left off "schema" - under which the NotMapped attribute is defined.