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");
Related
I am using EF Core 6.0 with MySQL (Pomelo.EntityFrameworkCore.MySql v6.0)
I am setting up my database via code first. Here are my 2 models (simplified):
public class Store : BaseEntity
{
public string Name { get; set; }
public virtual User? Owner { get; set; }
public int? OwnerId { get; set; }
}
public class User : BaseEntity
{
public string? Name { get; set; }
public virtual Store? Store { get; set; }
}
For both, I have
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
as the primary key (from BaseEntity).
I also have Lazy Loading enabled here:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
}
and in the Program.cs:
builder.Services.AddDbContext<AppDbContext>(opt => opt
.UseLazyLoadingProxies()
.ConfigureWarnings(warning => warning.Ignore(CoreEventId.DetachedLazyLoadingWarning))
.EnableSensitiveDataLogging()
.UseMySql(
Globals.DB_CONNECTION_STRING, new MySqlServerVersion(Globals.MYSQL_SERVER_VERSION),
o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)
));
Now, to the problem - I am trying to get a store from the database, using the following code:
Store? store = await dbContext.Stores
.Include(x => x.Owner)
.FirstOrDefaultAsync(x => x.Owner.Id == ownerId && x.Id == storeId);
I am getting the store details, but the Owner object and OwnerId is null. I can see the data in the database (e.g. I see OwnerId is set up for this specific store), but in the code, it is null.
I read on SO that Pomelo has some issues with setting up navigation properties, so I set it manually in OnModelCreating as follows:
modelBuilder.Entity<User>()
.HasOne(x => x.Store)
.WithOne(x => x.Owner)
;
But that didn't do the trick.
The same configuration works perfectly with MSSQL.
Any thoughts?
Thanks
Call HasForeignKey after WithOne and point to OwnerId.
I get an error ("Cannot convert lambda expression to type 'string' because it is not a delegate type") during converting the lambda expression in controller. I have 3 entities in as below:
Entities:
public class Student
{
public int ID { get; set; }
public string Course { get; set; }
public int CityID { get; set; }
public virtual City City { get; set; }
}
public class City
{
public int ID { get; set; }
public string Name { get; set; }
public int RegionID { get; set; }
public virtual Region Region { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class Region
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<City> Cities { get; set; }
}
Controller:
public ActionResult Index_Read([DataSourceRequest] DataSourceRequest request)
{
var dataContext = repository.Students;
var students = dataContext.ToDataSourceResult(request, m => new
{
ID = m.ID,
Course = m.Course,
City = m.City.Name, //I can get City name and show it in View.
MyRegionName = m.City.Region.Name //I can get region name and assign it to
//"MyRegionName" parameter in JSON. However in View I cannot get it using "MyRegionName" paremeter
});
return Json(students, JsonRequestBehavior.AllowGet);
}
View:
#model IEnumerable<Student>
#(Html.Kendo().Grid<Student>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(m => m.ID);
columns.Bound(m => m.Course);
columns.Bound(m => m.City);
columns.Bound(m => m.MyRegionName);
})
.Pageable()
.Sortable()
.Filterable()
.Scrollable()
.Groupable()
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("Index_Read", "Student"))
)
)
Here is the point that may cause the problem in the Controller and View:
City = m.City.Name, //I can get City name and show it in View.
MyRegionName = m.City.Region.Name //I can get region name and assign it to the "MyRegionName" parameter in JSON. However in View I cannot get it using "MyRegionName" paremeter.
May it be related to that there is City parameter in the Student entity. But there is no MyRegionName property in the City entity.
I assume this happens because there is no property called MyRegionName for the Student class.
You have two options
1) Create a ViewModel that looks like your Student model but make it has such property. Also make sure inside the projection function of the ToDataSourceResult you create those new ViewModel types instead of anonymous object.
2) Just use a Template column. e.g.
columns.Template(#<text></text>).Title("MyRegionName").ClientTemplate("#=MyRegionName#");
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
i m using EF Code First, and want to map an Entity class Person to entity table personTable as follows,
i have a an Entity Class
public class Person
{
public Guid Id
{
get;
set;
}
public string Email
{
get;
set;
}
public int Property
{
get;
set;
}
public Name Name
{
get;
set;
}
}
and a class for type of Property Name
public class Name
{
public string FirstName
{
get;
set;
}
public string FullName
{
get
{
return string.Format("{0} {1} {2}", FirstName, MiddleName, LastName);
}
}
public string LastName
{
get;
set;
}
public string MiddleName
{
get;
set;
}
}
i want to map person class to person table as follows
Person.Id => personTable.ID
Person.Name.FirstName ->personTable.FirstName
Person.Name.MiddleName => personTable.MiddleName
Person.Name.LastName => personTable.LastName
and so on....
where Person.Name is an object of type Name Class
Name is a complex type and you must EF tell this, otherwise it will consider Name as an entity and Person.Name as a navigation property. Mapping with Fluent API:
modelBuilder.ComplexType<Name>();
modelBuilder.Entity<Person>()
.Property(p => p.Name.FirstName)
.HasColumnName("FirstName");
modelBuilder.Entity<Person>()
.Property(p => p.Name.MiddleName)
.HasColumnName("MiddleName");
modelBuilder.Entity<Person>()
.Property(p => p.Name.LastName)
.HasColumnName("LastName");
I'm trying to model a self-referencing many to many in EF CodeFirst with a polymorphic table structure. I'm using the October 2011 CTP which supports navigation properties on derived types (which works well in other tests I've done).
The problem:
When I set up this particular many to many relationship in the base (abstract) table's mapping and try to get related records, I get a SQL query with hundreds of K of unions and joins...just the time taken to generate the SQL statement is 30 seconds, compared to bare milliseconds to execute it. However, it does return appropriate results. When I change the many to many to exist between two derived objects, the query produced is perfect...but I can't map the same relating M2M table again for other derived objects without being informed that the joining table has "already been mapped".
Specifics:
An existing database structure has a base table--Party--which is joined 1...1 or 0 with Customer, Vendor, User, and Department (each a type of Party).
Parties are related to each other via an existing join table PartyRelationship (ID, InternalPartyID, ExternalPartyID). By convention, InternalPartyID contains a User's PartyID and ExternalPartyID contains the PartyID of the Customer, Vendor, or Department with which they are associated.
Trying to use EF CodeFirst in a new project (WCF DataServices), I have created the Party class as:
public abstract class Party
{
public Party()
{
this.Addresses = new List<Address>();
this.PhoneNumbers = new List<PhoneNumber>();
this.InternalRelatedParties = new List<Party>();
this.ExternalRelatedParties = new List<Party>();
}
public int PartyID { get; set; }
public short Active { get; set; }
//other fields common to Parties
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
public virtual ICollection<Party> InternalRelatedParties { get; set; }
public virtual ICollection<Party> ExternalRelatedParties { get; set; }
}
Then, using TPT inheritance, Customer, Vendor, Department and User are similar to:
public class Customer : Party
{
public string TermsCode { get; set; }
public string DefaultFundsCode { get; set; }
//etc
}
public class User : Party
{
public string EmployeeNumber { get; set; }
public string LoginName { get; set; }
//etc
}
The joining table:
public class PartyRelationship
{
public int PartyRelationshipID { get; set; }
public int InternalPartyID { get; set; }
public int ExternalPartyID { get; set; }
//certain other fields specific to the relationship
}
Mappings:
public class PartyMap : EntityTypeConfiguration<Party>
{
public PartyMap()
{
// Primary Key
this.HasKey(t => t.PartyID);
// Properties
this.ToTable("Party");
this.Property(t => t.PartyID).HasColumnName("PartyID");
this.Property(t => t.Active).HasColumnName("Active");
//etc
// Relationships
this.HasMany(p => p.InternalRelatedParties)
.WithMany(rp => rp.ExternalRelatedParties)
.Map(p => p.ToTable("PartyRelationship")
.MapLeftKey("ExternalPartyID")
.MapRightKey("InternalPartyID"));
}
}
public class PartyRelationshipMap : EntityTypeConfiguration<PartyRelationship>
{
public PartyRelationshipMap()
{
// Primary Key
this.HasKey(t => t.PartyRelationshipID);
// Properties
// Table & Column Mappings
//this.ToTable("PartyRelationship"); // Commented out to prevent double-mapping
this.Property(t => t.PartyRelationshipID).HasColumnName("PartyRelationshipID");
this.Property(t => t.InternalPartyID).HasColumnName("InternalPartyID");
this.Property(t => t.ExternalPartyID).HasColumnName("ExternalPartyID");
this.Property(t => t.CreateTime).HasColumnName("CreateTime");
this.Property(t => t.CreateByID).HasColumnName("CreateByID");
this.Property(t => t.ChangeTime).HasColumnName("ChangeTime");
this.Property(t => t.ChangeByID).HasColumnName("ChangeByID");
}
}
Context:
public class MyDBContext : DbContext
{
public MyDBContext()
: base("name=MyDBName")
{
Database.SetInitializer<MyDBContext>(null);
this.Configuration.ProxyCreationEnabled = false;
}
public DbSet<Party> Parties { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
modelBuilder.Configurations.Add(new PartyMap());
modelBuilder.Configurations.Add(new PartyRelationshipMap());
}
}
A URL such as http://localhost:29004/Services/MyDataService.svc/Parties(142173)/SAData.Customer/InternalRelatedParties eventually returns correct oData but takes 30 seconds to produce an enormous SQL statement (189K) that executes in 600 ms.
I've also tried mapping the PartyRelationship table with a bidirectional one to many (both to Party as the "one" table), but with a similar outcome.
Do I need separate join tables for Customer-User, Vendor-User, and Department-User? Should I look at vertical table splitting or database views that separates PartyRelationship into separate logical entities (so I can remap the same table)? Is there another way the EF model should be configured in this scenario?