I have the following tables and cannot edit their structure...
Person
------
Id PK
Code
Name
Order
-----
Id PK
Person_Code
OrderDetails
Now in my Person class I want to have a list of Orders for that person, but I'm not entirely sure how to go about setting up the mapping in fluent nhibernate to match on the Code column rather than the ID. There is no foreign key constraint and I am unable to change the database to use the keys. Something like this is what I require, but can;t seem to figure out the mapping.
public class Person
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
public virtual IList<Order> Orders { get; private set; }
}
public class Order
{
public virtual int Id { get; set; }
public virtual string OrderDetails { get; set; }
public virtual Person Owner { get; set; }
}
You define your column with the KeyColumn method. It should work regardless of existence of a foreign key constraint.
class PersonMap : ClassMap<Person>
{
public PersonMap()
{
HasMany(p => p.Order)
.KeyColumn("Person_Code")
.PropertyRef("Code");
}
}
PropertyRef method is available from rev 614 so you may need to update the fluent nhibernate version.
Related
In my project I have noticed that I will be have a lot of dictionaries with the same structure:
shortcut
full name for tooltip
which will be used on many different business forms.
I started to thing that there is no sense to keep all of them in separate tables.
It is better to keep all of them in one table and provide an additional column (DictionaryType) which will separate them in the case of asking the database for data?
So one repository with such method
public class DictionaryEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public DictionaryType Type { get; set; }
}
public async Task<IEnumerable<DictionaryEntity> GetDictionaries(DictionaryType type)
{
return await _dbContext.Dictionaries.Where(d => d.DictionaryType == type).ToArrayAsync();
}
If new dictionaries appear, I need to only extend DictionaryType and I don't need to worry about database changes or repo/service/controller changes.
For now it is nice and easy, but... I would like to configure foreign key in business entities in that way:
public class CarEntity
{
public Guid Id { get; set; }
public Guid ModelTypeId { get; set;}
public DictionaryEntity ModelType { get; set;}
public Guid PetrolTypeId { get; set;}
public DictionaryEntity PetrolType { get; set;}
}
How to configure in EF Core, foreign key in that way where:
CarEntity.ModelTypeId points to DictionaryEntity.Id and DictionaryEntity.Type = DctionaryType.ModelType ?
CarEntity.PetrolTypeId points to DictionaryEntity.Id and DictionaryEntity.Type = DctionaryType.PetrolType ?
I read, that there is something like a composite foreign key, so I could do FK on { dict.Name, dict.Type } but it demands from me to keep in CarEntity as many properties as composite foreign key have.
Is there a chance to do unique constraint across multiple tables ?
Something like this:
modelBuilder.Entity<CarEntity>()
.HasCheckConstraint("CK_ModelType", "[ModelTypeId] IS NOT NULL AND [Document].[Type] = 'ModelType'", c => c.HasName("CK_ModelType_Dictionary"));
I'm trying to make one to one relationship. I don't want to use fluent API if it is not necessary. This is what I tried so far:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
public class Person
{
public int Id { get; set; }
[ForeignKey("UserId")]
public UserProfile UserProfile { get; set; }
}
Yes, I know there are few similar questions outhere, but none of them were short and clear. Lot of them also did not work.
It depends a little on what type of table structure you want to achieve. There are various ways of doing this, and there is a good walkthrough for all the options, from Shared Primary Key Assocations to One-to-One Foreign Key Associations in those links. Unfortunately those links make more use of Fluent than Annotations. The samples below use Annotations, as you need.
Shared Primary Key
In theory the Shared Primary Key (horizontal table partitioning, in database terms) is the "correct way". It is also the smallest change you need to do to be able to generate a migration (which will use a Shared Primary Key Association). Note that I would change Person.Id to Person.UserId to better show your intent:
// tested in EF 5 and MVC 4.5.
[Table("UserProfile")]
public class UserProfile {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
[Table("Person")] // not required, added for clarity in sample code
public class Person {
// Note the change of property name to reflect that this is a shared primary key,
// using the UserId column in UserProfile as the Primary Key
[Key]
public int UserId { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile UserProfile { get; set; }
}
// The generated migration:
public partial class AddTable_Person : DbMigration
{
public override void Up() {
CreateTable(
"dbo.Person",
c => new {
UserId = c.Int(nullable: false),
})
.PrimaryKey(t => t.UserId)
.ForeignKey("dbo.UserProfile", t => t.UserId)
.Index(t => t.UserId);
}
public override void Down(){
DropIndex("dbo.Person", new[] { "UserId" });
DropForeignKey("dbo.Person", "UserId", "dbo.UserProfile");
DropTable("dbo.Person");
}
}
this then gives you, in effect a 1:0-1 relationship between UserProfile (which is mandatory) and People (which is optional, but can have one per person at the most.
If you want to use Id in Person then do the following (the migration will change accordingly):
public class Person {
public int Id { get; set; }
[ForeignKey("Id")]
public UserProfile UserProfile { get; set; }
}
Shared Primary Key with two-way navigation
If you want to navigate from UserProfile to Person you have more work to do. Simply adding public virtual Person Person { get; set; } to UserProfile will give you an error:
Unable to determine the principal end of an association between the types 'Test.Models.UserProfile' and 'Test.Models.Person'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
So, we fix it with [Required] on the Person.UserProfile property (Person requires UserProfile). This gives the same migration as before.
// tested in EF 5 and MVC 4.5.
[Table("UserProfile")]
public class UserProfile {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
[ForeignKey("UserId")]
public virtual Person Person { get; set; }
}
[Table("Person")] // not required, added for clarity in sample code
public class Person {
[Key]
public int UserId { get; set; }
[ForeignKey("UserId")]
[Required]
public virtual UserProfile UserProfile { get; set; }
}
Again, this works if you use Id for Person instead of UserId:
public class Person {
[Key]
public int Id { get; set; }
[ForeignKey("Id")]
[Required]
public virtual UserProfile UserProfile { get; set; }
}
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual Person Person {get;set;}
}
public class Person
{
public int Id { get; set; }
public int UserProfileUserId { get; set; } //Foreign Key
public virtual UserProfile UserProfile { get; set; }
}
If you want to create a one-to-one relationship the first thing you must clarify is what is the principal and what the dependent entity in this relationship. Can a Person exist without UserProfile or can a UserProfile exist without Person?
Because you have started to apply a [ForeignKey] attribute in Person I am assuming now that Person is the dependent, i.e. it cannot exist without UserProfile.
Correct application of the [ForeignKey] attribute would then be:
public class Person
{
[ForeignKey("UserProfile")]
public int Id { get; set; }
public UserProfile UserProfile { get; set; }
}
I am not sure if that is sufficient because you don't have a Person navigation property in UserProfile. If it doesn't work add this property to UserProfile:
public Person Person { get; set; }
If you don't want to have such a navigation property you can't avoid Fluent API:
modelBuilder.Entity<Person>()
.HasRequired(p => p.UserProfile)
.WithOptional();
I have a parent and child table and entites are created and mapped using one to many relation ship. On one to many side when i use Inverse() then the child table's foreign key value is inserted as null.
public class TableA
{
public virtual long ID { get; set; }
public virtual string Name { get; set; }
public virtual IList<TableB> TableB { get; set; }
}
public class TableB
{
public virtual long ID { get; set; }
public virtual string Name { get; set; }
public virtual TableA TableA { get; set; }
}
public class TableAMap : ClassMap<TableA>
{
public TableAMap()
{
Id(x=>x.ID);
Map(x=>x.Name).Column("Name");
HasMany(x=>x.TableB)
.KeyColumn("TableA_ID")
.Inverse()
.Cascase.All()
.Not.LazyLoad();
}
}
public class TableBMap : ClassMap<TableB>
{
public TableBMap()
{
Id(x=>x.ID);
Map(x=>x.Name).Column("Name");
References(x=>x.TableA).Column("TableA_ID").Not.LazyLoad();
}
}
Note When the Inverse() is removed from many to one the new records are inserted without any issues and the foreign key is inserted without any issues but when i update a record the foreign key of the existing records are replaced as null.
Please help me i looked in to similar questions but it doesn't help me.
Fluent NHibernate one-to-many relationship setting foreign key to null
Refer to this link which has the solution for this issue.
Refer this Solution link
The map class should be:
public class TableAMap : ClassMap<TableA>
{
public TableAMap()
{
Id(x=>x.ID);
Map(x=>x.Name).Column("Name");
HasMany<TableB>(x=>x.TableB)
.KeyColumn("TableA_ID")
.Cascade.All().Inverse();
}
}
public class TableBMap : ClassMap<TableB>
{
public TableBMap()
{
Id(x=>x.ID);
Map(x=>x.Name).Column("Name");
References<TableA>(x=>x.TableA).Column("TableA_ID").Not.Nullable();
}
}
it's hard to tell exactly without seeing the code which inserts. However my crystal ball tells me you probably forgot the last line
Parent parent = new Parent();
Child child = new Child();
parent.Children.Add(child);
child.Parent = parent; <-- this is important because this will maintain the foreign key
I am attempting to use NHibernate to generate a model for a very odd database. The tables themselves have primary keys for show only, all the actual relationships are on unique columns. For example, a product table with a product id primary key and a unique product name column. Another table, demand, has a product name column and that defines the relationship. I know this situation isn't ideal but it's out of my control.
At any rate, I was able to use Fluent NHibrenate to map product to demand, but I cannot seem to get the entity to lazy-load.
public class Demand
{
public virtual DemandId { get; set; }
public virtual Product { get; set; }
}
public class DemandMap : ClassMap<Demand>
{
public DemandMap()
{
this.Table("Demand");
this.LazyLoad();
this.Id(x => x.DemandId);
this.References(x => x.Product).PropertyRef(x => x.ProductName).LazyLoad();
}
}
Does anyone have any insight into why lazy loading is not working? I know it is not because I can see the product being fetched along with the demand in the SQL profiler.
My idea (Maybe you can try use "HasMany" there is example but you can read something about this):
First class
public class Demand
{
public virtual int DemandId { get; set; }
public virtual int Product { get; set; }
public virtual IEnumerable<NewClass> Name {get; set;}
}
this.HasMany(x=> x.Product).Column("Product_id").not.nullable;
Second class
public class NewClass
{
public virtual Demand Product_id {get; set;}
}
this.References(x => x.Product).Column("product_id).not.nullable
How can I map one-to-many relationship with
User to Address,
Customer to Address,
Agency to Address and
store in a single Address Table using Fluent NHibernate
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Customer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Agency
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Address
{
public virtual int Id { get; set; }
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
}
I think you'll need to store your relations independently to connect addresses and users/customers/agencies if you want to be able to use the same address for all types. This involves introducing a new table that only stores ID pairs, and making that the storage location for your relationship.
You can map collections as many-to-many and use the table method to name your link table. Your mapping would look something like:
public UserMap : ClassMap<User> {
Id (u => u.Id);
Map (u => u.Name);
HasManyToMany (u => u.Addresses).Table ("UsersXAddresses");
}
You'll need a similar link table for customers and agencies.
In the constructor for your mapping class, map the link using the HasMany method. HasMany will create a one-to-many relationship. HasManyToMany will create a many-to-many relationship.
For example: HasMany(x => x.Address).LazyLoad();
This will create a one-to-many relationship between the User class and the Address class.
For the many-to-many, you will also need to specify the table name and if you so desire, the left and right side table mappings.
For example: HasManyToMany(x => x.Address).Table("AddressToUser").ParentKeyColumn("AddressId").ChildKeyColumn("UserId").LazyLoad();
If you decide that you want to set up a distinction between a UserAddress and an AgencyAddress (where these are sub-classes of Address) - you can use the DiscriminateSubClassesOnColumn method in the AddressMap class so the FNH knows to create an extra column in order to determine which type of object to create.
For example: DiscriminateSubClassesOnColumn("Type").AlwaysSelectWithValue();
You should be able to use FNH Automapping to map these classes "as is".
It will handle all the relationships in your object model.
I believe it will put all the addresses in a single Address table as you desire, but can't say for sure.