I trying to create inheritance so I can have some super classes with general properties and then more specialized classes that are the ones getting used.
I want something like the Table per type or table per class they make here http://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat
So I have my supertype Game here
public abstract class Game
{
public virtual int Id { get; set; }
public virtual List<UserGame> UserList { get; set; }
}
public class GameMap : ClassMap<Game>
{
public GameMap()
{
Id(x => x.Id, "GameId")
.GeneratedBy
.HiLo("100");
HasMany(x => x.UserList)
.Cascade.All();
}
}
And then my specialized class here QMGameActive
public class QMGameActive : Game
{
public virtual DateTime LastUpdate { get; set; }
public virtual string SelectedBrick { get; set; }
public virtual int Score { get; set; }
public virtual string History { get; set; }
public virtual int StartingPlayerId { get; set; }
public QMGameActive()
{
LastUpdate = DateTime.Now;
History = "";
SelectedBrick = "";
}
}
public class QMGameActiveMap : SubclassMap<QMGameActive>
{
public QMGameActiveMap()
{
KeyColumn("GameId");
Map(x => x.LastUpdate);
Map(x => x.SelectedBrick);
Map(x => x.Score);
Map(x => x.History);
Map(x => x.StartingPlayerId);
}
}
But when I get a diagram from the server I can see there is no connection between Game and QMGameActive there
So what am I missing to make it use inheritance?
I am fairly sure that if you KeyColumn("GameId"); from the QMGameActiveMap() then NHibernate will generate QMGameActive with an ID Column of GameID which will be a foreign key of Game.GameId. which would seem to give you what you want.
(sorry away from home and cannot try code out to make sure).
Related
I have users which have many roles
public class User
{
public int Id {get;set;}
public string Name {get;set;}
public List<Role> Roles {get;set;}
}
public class Roles
{
public int Id {get;set;}
public string Key{get;set;}
}
public class UserRoles
{
public int UserId {get;set;}
public int RoleId {get;set;}
}
what I try to achieve is getting a user with all its roles in one query, but so far I failed.
For Mapping I use a custom Conventionbased mapper (I can provide the code, but it's rather big)
I tried FetchOneToMany and I tried Fetch as described here
https://github.com/schotime/NPoco/wiki/One-to-Many-Query-Helpers
https://github.com/schotime/NPoco/wiki/Version-3
But Roles is always empty.
Role and User by itself are mapped correctly and I did try to specify the relation like
For<User>().Columns(x =>
{
x.Many(c => c.Roles);
x.Column(c => c.Roles).ComplexMapping();
}, true);
Again it didn't help, roles is empty.
I have no idea what I'm missing.
Any ideas?
ComplexMapping and relationship mapping(1-to-n, n-to-n) are two different things.
ComplexMapping is for mapping nested objects for data that usually resides in the same table where there is a one-to-one relationship. For something like this:
public class Client
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
public Client()
{
Address = new Address();
}
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Telephone { get; set; }
public string Country{ get; set; }
}
If you're using a convention-based mapper your override would look something like this:
For<Client>().Columns(x =>
{
x.Column(y => y.Address).ComplexMapping();
});
One thing to watch for when using a convention-based mapper; you have to enable ComplexMapping in your scanner with the following code:
scanner.Columns.ComplexPropertiesWhere(y => ColumnInfo.FromMemberInfo(y).ComplexMapping);
Otherwise ComplexMapping() calls in your overrides will simply be ignored.
One-to-Many mapping would work like this (see NPoco on Github for more):
For<One>()
.TableName("Ones")
.PrimaryKey(x => x.OneId)
.Columns(x =>
{
x.Column(y => y.OneId);
x.Column(y => y.Name);
x.Many(y => y.Items).WithName("OneId").Reference(y => y.OneId);
}, true);
For<Many>()
.TableName("Manys")
.PrimaryKey(x => x.ManyId)
.Columns(x =>
{
x.Column(y => y.ManyId);
x.Column(y => y.Value);
x.Column(y => y.Currency);
x.Column(y => y.OneId);
x.Column(y => y.One).WithName("OneId").Reference(y => y.OneId, ReferenceType.OneToOne);
}, true);
is there anyone who could tell me how can i do the corresponding table mapping with entity framework code first.
Here is my table
enter link description here
i've tried to do this but without any success.
[Table("Matiere")]
public class Matiere
{
[Key]
public Int32 Id { get; set; }
public Int32? IdParent { get; set; }
[Column("NomMatiere")]
public String Nom { get; set; }
public virtual Matiere Parent { get; set; }
public virtual ICollection<Matiere> Childs { get; set; }
}
public class MatiereConfiguration : EntityTypeConfiguration<Matiere>
{
public MatiereConfiguration()
{
this.HasOptional(m => m.Parent).WithMany(m => m.Childs).HasForeignKey(m => m.IdParent);
this.HasOptional(m => m.Childs).WithRequired();
}
}
thanks in advance.
You're close. I do not think you need to supply the HasOptional(m => m.Childs).WithRequired();
First, I would put all of your mapping information into your MatiereConfiguration instead of using a mix of DataAnnotations and Fluent mappings. It's not required, but just a suggestion.
This should work:
public class MatiereConfiguration : EntityTypeConfiguration<Matiere>
{
public MatiereConfiguration()
{
HasKey(m => m.Id);
Property(m => m.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(m => m.Nom).HasColumnName("NomMatiere")
HasOptional(m => m.Parent).WithMany(m => m.Childs).HasForeignKey(m => m.IdParent);
}
}
I am new to EF, and trying to get many-to-many unidirectional relationship with code first approach. For example, if I have following two classes (not my real model) with be a N * N relationship between them, but no navigation property from "Customer" side.
public class User {
public int UserId { get; set; }
public string Email { get; set; }
public ICollection TaggedCustomers { get; set; }
}
public class Customer {
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
The mapping code looks like ...
modelBuilder.Entity()
.HasMany(r => r.TaggedCustomers)
.WithMany(c => c.ANavgiationPropertyWhichIDontWant)
.Map(m =>
{
m.MapLeftKey("UserId");
m.MapRightKey("CustomerId");
m.ToTable("BridgeTableForCustomerAndUser");
});
This syntax force me to have "WithMany" for "Customer" entity.
The following url, says "By convention, Code First always interprets a unidirectional relationship as one-to-many."
Is it possible to override it, or should I use any other approach?
Use this:
public class User {
public int UserId { get; set; }
public string Email { get; set; }
// You must use generic collection
public virtual ICollection<Customer> TaggedCustomers { get; set; }
}
public class Customer {
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
And map it with:
modelBuilder.Entity<User>()
.HasMany(r => r.TaggedCustomers)
.WithMany() // No navigation property here
.Map(m =>
{
m.MapLeftKey("UserId");
m.MapRightKey("CustomerId");
m.ToTable("BridgeTableForCustomerAndUser");
});
I have a class with multiple many to many relationships mapping to the same secondary class. My EquipmentSet class has two arrays of Equipment objects, and the Equipment class also has an array of EquipmentSets to determine which sets the equipment is a part of.
EF is only generating a lookup table for the second Many to Many relationship. How can I tell EF to generate lookup tables for both? When the code below is used, only the table "ModelSpecificEquipment" is generated. The table "GlobalEquipment" never gets generated.
public partial class EquipmentSet
{
public int Id { get; set; }
public List<Equipment> Global { get; protected set; }
public List<Equipment> ModelSpecific { get; protected set; }
public EquipmentSet()
{
Global = new List<Equipment>();
ModelSpecific = new List<Equipment>();
}
}
public partial class Equipment
{
public int Id { get; set; }
public List<EquipmentSet> EquipmentSets { get; set; }
public Equipment()
{
}
}
public class DataContext : DbContext
{
public DbSet<Equipment> Equipment { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Equipment>()
.HasMany<EquipmentSet>(x => x.EquipmentSets)
.WithMany(x => x.Global)
.Map(x =>
{
x.MapLeftKey("EquipmentId");
x.MapRightKey("EquipmentSetId");
x.ToTable("GlobalEquipment");
});
modelBuilder.Entity<Equipment>()
.HasMany<EquipmentSet>(x => x.EquipmentSets)
.WithMany(x => x.ModelSpecific)
.Map(x =>
{
x.MapLeftKey("EquipmentId");
x.MapRightKey("EquipmentSetId");
x.ToTable("ModelSpecificEquipment");
});
base.OnModelCreating(modelBuilder);
}
}
Again, at this point the database that EF creates only contains 3 tables: EquipmentSets, Equipments, ModelSpecificEquipments. GlobalEquipments is missing.
I think it is not possible to map this. You cannot relate two endpoints on one side to one single endpoint on the other side of a relationship. You will probably need something like this:
public partial class Equipment
{
public int Id { get; set; }
public List<EquipmentSet> GlobalEquipmentSets { get; set; }
public List<EquipmentSet> ModelSpecificEquipmentSets { get; set; }
public IEnumerable<EquipmentSet> EquipmentSets
{
get
{
return GlobalEquipmentSets.Concat(ModelSpecificEquipmentSets);
// catch cases when one or both of the sets are null.
}
}
}
EquipmentSets is here only a readonly helper which isn't mapped to the database.
You can then create a many-to-many relationship between Global and GlobalEquipmentSets and another many-to-many relationship between ModelSpecific and ModelSpecificEquipmentSets.
I have a little problem with fluentNhibernate and MySQL.
I would like to map my entity:
public class Topic
{
public Topic()
{
ParentTopic = null;
}
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual DateTime CreatedAt { get; private set; }
public virtual Guid CreatedBy { get; set; }
public virtual IList<Post> Posts { get; set; }
public virtual Topic ParentTopic { get; set; }
}
To a table with the same name. My bigest problem is how to I do the mapping of the CreatedAt so that in the database I get a timestamp that is only changed on insert and ignored when updating.
thx ;)
Found the answer to my little problem :)
public class TopicMap : ClassMap<Topic>
{
public TopicMap()
{
Table("Topics");
Id(t => t.Id).GeneratedBy.Guid();
Map(t => t.CreatedAt).Not.Nullable().Generated.Insert().CustomSqlType("timestamp");
Map(t => t.CreatedBy).Not.Nullable();
Map(t => t.Name).Not.Nullable().Length(500);
HasMany(t => t.Posts);
References(t => t.ParentTopic).Nullable().Cascade.All().ForeignKey("FK_Topic_ParentTopic");
}
}
This seams to work in my unit tests. Hope that it will not produce any greater problems in the future.
If anybody seas a problem with this then please let me know.