Nhibernate map multiple tables to a same list - mysql

I have multiple objects meaning various steps (each object is a step) from a flux, they are to be persisted in the DB.
I was thinking on creating a relational table, where I would have each association, only one relation per row. something like, per example:
Steps: Id, Course_Id, Evaluation_Id, ProcessEvaluation_Id
and to clarify:
StepsForClass: id, class_id, steps_id
Course:id, someMoreinfo
Evaluation: id, someOtherinfo
and so on...
to be referenced in the table:
Class: Id, StepsForClass_id, someInfo
How could I map this into something like:
public class Klass
{
public uint Id { get; set; }
public IList<Step> Steps { get; set; }
}
public abstract class Step
{
public uint Id { get; set; }
public abstract void Apply();
}
public class Course : Step
{
//( some more fields )
public override void Apply() { /* ... */ }
}
public class Evaluation : Step
{
//( some other more fields )
public override void Apply() { /* ... */ }
}

You can use inheritence mapping like this:
<class name="Step" table="STEP">
<id name="Id" type="Int64" column="STEP_ID">
<generator class="native"/>
</id>
<property name="Amount" column="AMOUNT"/>
...
<joined-subclass name="Course" table="COURSE">
<key column="STEP_ID"/>
...
</joined-subclass>
<joined-subclass name="Evaluation" table="EVALUATION">
<key column="STEP_ID"/>
...
</joined-subclass>
</class>
For further reading: inheritance mapping

Related

System.IndexOutOfRangeException: Could not find specified column in results using n-hibernate

I am new to fluent n-hibernate.
I am using fluent nHibernate to connect to the MYSQL Database in my application. The Mapping class for the result set is declared as below:
public class ProcResult
{
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual string Price { get; set; }
public virtual int AddressID { get; set; }
public virtual string Address { get; set; }
public virtual string Pincode { get; set; }
}
I have created a routine(Procedure) in MY SQL as :
CREATE DEFINER=`root`#`localhost` PROCEDURE `testProc`()
BEGIN
select a.ID, a.Name, a.Price, a.AddressID, b.Address, b.Pincode from expediads a join adresses b on a.addressid=b.id;
END
The hbm.xml file is for routine(stored procedure) is :
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="TestHBN">
<sql-query name="testProc">
<return alias="PR" class="TestHBN.Models.ProcResult, TestHBN">
<return-property name="ID" column="ID"/>
<return-property name="Name" column="Name" />
<return-property name="Price" column="Price" />
<return-property name="AddressID" column="AddressID" />
<return-property name="address" column="address" />
<return-property name="pincode" column="pincode" />
</return>
Call testProc;
</sql-query>
</hibernate-mapping>
Also this is the mapping for the result-set class:
public class ProcResultMap : ClassMap<ProcResult>
{
public ProcResultMap()
{
Id(x => x.ID).GeneratedBy.Identity().Column("ID");
Map(x => x.Name).Column("Name");
Map(x => x.Price).Column("Price");
Map(x => x.AddressID).Column("AddressID");
Map(x => x.Address).Column("Address");
Map(x => x.Pincode).Column("Pincode");
}
}
The stored procedure returns data from two tables "expediads" and "adresses". But I want the result-set to be stored in custom class as declared as "ProcResult" here.
I am getting following error:
System.IndexOutOfRangeException: Could not find specified column in
results: Address2_0_
Thanks,
Saloni
I don't think that you want to declare the ID as an identity column, as it is not generated as part of the stored procedure. Try simply defining it as an id column.
Id(x => x.ID).Column("ID");

The number of members in the conceptual type does not match

I am using entity framework code first with dotConnect for MySQL, and for some reason I get an error about one of my models mapping.
I've searched this error and it is usually caused by bad xml file or entity framework specific files. I am not using any of these, only a .cs code file with the models.
Exception Details:
System.Data.MappingException: The number of members in the conceptual
type 'SiteModels.TournamentTable' does not match with the number of
members on the object side type 'SiteModels.TournamentTable'. Make
sure the number of members are the same.
I have no idea why I am getting this error, since I don't have any designer,
only one file containing the code.
Here is the problematic class:
public class TournamentTable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public List<TournamentColumn> Columns { get; set; }
public TournamentTable()
{
Columns = new List<TournamentColumn>();
}
public void AddColumn(int index, TournamentColumn column)
{
Columns.Insert(index, column);
}
public void RemoveColumn(int index)
{
Columns.RemoveAt(index);
}
/// <summary>
/// Add a tournament cell at the top of the column.
/// </summary>
/// <param name="column"></param>
public void AddColumn(TournamentColumn column)
{
Columns.Add(column);
}
/// <summary>
/// Returns the tournament column at the index specified.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public TournamentColumn this[int index]
{
get { return Columns[index]; }
}
/// <summary>
/// Returns the tournament cell at the index specified.
/// </summary>
/// <param name="columnIndex"></param>
/// <param name="cellIndex"></param>
/// <returns></returns>
public TournamentCell this[int columnIndex, int cellIndex]
{
get { return Columns[columnIndex][cellIndex]; }
set
{
Columns[columnIndex][cellIndex] = value;
}
}
}
Context configuration:
public class EntitiesContext : DbContext
{
public EntitiesContext()
: base()
{
System.Data.Entity.Database.SetInitializer<EntitiesContext>(new DropCreateDatabaseIfModelChanges<EntitiesContext>());
}
public EntitiesContext(DbConnection connection)
: base(connection, true)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions
.Remove<System.Data.Entity.ModelConfiguration.Conventions
.ColumnTypeCasingConvention>();
}
public DbSet<User> Users { get; set; }
public DbSet<Player> Players { get; set; }
public DbSet<Game> Games { get; set; }
public DbSet<TournamentTable> TournamentTables { get; set; }
}
Thanks for the help, I don't have any clue.
Try commenting out the indexers and see if it helps. If it does you may need to put NotMapped attribute on them or reimplement them as methods.

How can I populate a FK field using EF Code First?

I have a class Mailout with a Status that looks like this:
public class Mailout
{
public int Id {get; set; }
public string Name {get; set; }
public MailoutStatus Status { get; set; }
}
public class MailoutStatus
{
public int Id { get; set; }
public string Name { get; set;}
}
When I insert Mailouts and set the Status property, they are inserted correctly. When I fetch them, Status is always null. Since I don't have (and don't want) the status ID on my Mailout class, I have no way to retrieve it after-the-fact. How do I tell EF to populate this field eagerly, rather than lazily?
I'm hoping I can set something up in OnModelCreating() since I want this behavior all the time, not as an option that I can use sometimes by manipulating my LINQ-to-Entities queries.
You need to make your navigation properties virtual.
There is no such option in the ModelBuilder to configure an automatic eager loading of navigation properties in each query. You have to specify it query by query. As a workaround you could encapsulate eager loading in some method or property, for instance in the context:
public class MyContext : DbContext
{
public DbSet<Mailout> Mailouts { get; set; }
public IQueryable<Mailout> MailoutsWithStatus
{
get { return Mailouts.Include(m => m.Status); }
}
// ...
}
And then use in your queries:
context.MailoutsWithStatus.Where(...) ... etc.
Only an idea, it's untested.
Taking from Employee Info Starter Kit - upcoming MVC edition, here is a snippet, that works pretty well, to eager load objects when used:
public class Employee
{
...
public int? ReportsTo { get; set; }
[ForeignKey("ReportsTo")]
public virtual Employee Supervisor { get; set; }
/// <summary>
/// Children object collection of foreign key relation
/// </summary>
public virtual List<Employee> Subordinates { get; set; }
}

EF 4.1 Multiple Many to Many relationships in single class

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.

Nhibernate Guid with PK MySQL

I've got a question. I use NHibernate with MySql. At my entities I use Id(PK) for my business-logic usage and Guid(for replication). So my BaseDomain:
public class BaseDomain
{
public virtual int Id { get; set; }
public virtual Guid Guid { get; set; }
public class Properties
{
public const string Id = "Id";
public const string Guid = "Guid";
}
public BaseDomain() { }
}
My usage domain:
public class ActivityCategory : BaseDomain
{
public ActivityCategory() { }
public virtual string Name { get; set; }
public new class Properties
{
public const string Id = "Id";
public const string Guid = "Guid";
public const string Name = "Name";
private Properties() { }
}
}
Mapping:
<class name="ActivityCategory, Clients.Core" table='Activity_category'>
<id name="Id" unsaved-value="0" type="int">
<column name="Id" not-null="true"/>
<generator class="native"/>
</id>
<property name="Guid"/>
<property name="Name"/>
</class>
But when I insert my entity:
[Test]
public void Test()
{
ActivityCategory ac = new ActivityCategory();
ac.Name = "Test";
using (var repo = new Repository<ActivityCategory>())
repo.Save(ac);
}
I always get '00000000-0000-0000-0000-000000000000' at my Guid field.
What should I do for generate right Guid. May be mapping?
Thanks a lot!
From a NHibernate perspective, you should either set the guid in C# or tell NHibernate that it is generated by the database.
In the former case, set the guid property in the constructor.
public class BaseDomain
{
public BaseDomain()
{
Guid = Guid.NewGuid();
}
}
You map a property whose value is generated in the database like this. Depending on how the value is generated, you may also need to exclude the property from insert statements.
<class name="ActivityCategory, Clients.Core" table="Activity_category">
<id name="Id" not-null="true" >
<generator class="native" />
</id>
<property name="Guid" generated="insert" insert="false" update="false" />
<property name="Name" />
</class>