I'm have a issue,
i'm studyng nhibernate with c# and .net core, but i dont know how to procede on this case.
i create my table with 2FK:
public class Venda
{
public Venda()
{
VendaId = Guid.NewGuid();
DataVenda = DateTime.Now;
}
public virtual Guid VendaId { get; set; }
public virtual Guid BombomId { get; set; }
public virtual Guid ClienteId { get; set; }
public virtual DateTime DataVenda { get; set; }
public virtual IList<Bombom> Bomboms { get; set; }
public virtual IList<Cliente> Clientes { get; set; }
}
My migration is
[FluentMigrator.Migration(2)]
public class CreateTableVenda : FluentMigrator.Migration
{
public override void Up()
{
Create.Table("Venda")
.WithColumn("VendaId").AsGuid().NotNullable().PrimaryKey().Indexed()
.WithColumn("DataVenda").AsDateTime().NotNullable()
.WithColumn("BombomId").AsGuid().NotNullable().Indexed()
.WithColumn("ClienteId").AsGuid().NotNullable().Indexed();
Create.ForeignKey().FromTable("Venda").ForeignColumn("BombomId")
.ToTable("Bombom").PrimaryColumn("BombomId");
Create.ForeignKey().FromTable("Venda").ForeignColumn("ClienteId")
.ToTable("Cliente").PrimaryColumn("ClienteId");
}
public override void Down()
{
Delete.Table("Venda");
}
}
But my mapping, i'm have issues, because i want to LAZYLOAD the map entity together when i get
public class VendaMap : ClassMap<Venda>
{
public VendaMap()
{
Id(x => x.VendaId);
Map(x => x.DataVenda);
Map(x => x.BombomId).Column("Bombom").Access.CamelCaseField();
Map(x => x.ClienteId);
LazyLoad();
}
}
Could someone help me please?
Related
I'm trying to create a one-to-many map, I tried a lot ways to do that, but I just I haven't figured it out yet :/
I have 2 entites, Wallet and Transfer, I want to add in Transfer a FK WalletId, so one transfer has just one wallet, but a wallet can be related to more than one transfer.
Wallet.cs -
public class Wallet
{
public int Id { get; private set; }
public decimal Balance { get; private set; }
}
Transfer.cs -
public class Transfer
{
#region Properties
public int Id { get; private set; }
public decimal Value { get; private set; }
public DateTime? TransferDate { get; private set; }
public DateTime RegisterDate { get; private set; }
public ETransferType TransferType { get; private set; }
}
WalletMap.cs -
public class WalletMap : IEntityTypeConfiguration<Wallet>
{
public void Configure(EntityTypeBuilder<Wallet> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Balance).HasColumnType("Money").IsRequired();
}
}
TransferMap.cs -
public class TransferMap : IEntityTypeConfiguration<Transfer>
{
public void Configure(EntityTypeBuilder<Transfer> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Value).HasColumnType("Money").IsRequired();
builder.Property(x => x.TransferDate);
builder.Property(x => x.RegisterDate).IsRequired();
builder.Property(x => x.TransferType).IsRequired();
}
}
Add a foreign key and navigation property:
public class Wallet
{
public int Id { get; set; }
public decimal Balance { get; set; }
public virtual ICollection<Transfer> Transfers { get; set; } // Navigation Property
}
public class Transfer
{
pubic int Id { get; private set; }
public decimal Value { get; private set; }
public Datetime? TransferDate { get; private set; }
//.....Remaining properties
public int WalletId { get; set; } //Foreign Key
public virtual Wallet Wallet { get; set; } //Reference Navigation
}
This will add the foreign key and navigation properties needed.
//using fluent api
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Transfer>().HasOne(x => x.Wallet)
.WithMany(x => x.Transfers)
.HasForeignKey(x => x.WalletId);
modelBuilder.Entity<Wallet>.HasMany(x => x.Transfers)
.WithOne();
}
To Wallet.cs add:
public virtual ICollection<Transfer> Tranfers { get; set; }
To Transfer.cs add:
public virtual Wallet Wallet { get; set; }
To TransferMap.cs add in your Configure block:
builder.HasRequired(x => x.Wallet).WithMany(x => x.Transfers).Map(x => x.MapKey("WalletId")).WillCascadeOnDelete();
You can remove the WillCascadeOnDelete() if you have not configured a cascading delete in the database. This assumes you already have WalletId defined in your Transfers table in the database.
I'm using EF Core 2.1 and I have these class in my Domain.
public class HomeSection2
{
public HomeSection2()
{
HomeSection2Detail = new List<HomeSection2Detail>();
}
public Guid ID { get; set; }
public string Title { get; set; }
public string Header { get; set; }
public List<HomeSection2Detail> HomeSection2Detail { get; set; }
}
public class HomeSection2Detail
{
public Guid ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Link { get; set; }
public int? Sequence { get; set; }
public HomeSection2 HomeSection2 { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.RemovePluralizingTableNameConvention();
//HomeSection2
modelBuilder.Entity<HomeSection2>().HasKey(s => s.ID);
modelBuilder.Entity<HomeSection2>().Property(s => s.ID).ValueGeneratedOnAdd();
modelBuilder.Entity<HomeSection2>().Property(s => s.Title).IsRequired();
modelBuilder.Entity<HomeSection2>().Property(s => s.Header).IsRequired();
//HomeSection2Detail
modelBuilder.Entity<HomeSection2Detail>()
.HasOne(p => p.HomeSection2)
.WithMany(b => b.HomeSection2Detail);
modelBuilder.Entity<HomeSection2Detail>().HasKey(s => s.ID);
modelBuilder.Entity<HomeSection2Detail>().Property(s => s.ID).ValueGeneratedOnAdd();
modelBuilder.Entity<HomeSection2Detail>().Property(s => s.Title).IsRequired();
modelBuilder.Entity<HomeSection2Detail>().Property(s => s.Sequence).IsRequired();
}
And I have a generic repo
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
Context = context;
}
public IEnumerable<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}
}
When I call GetAll from the Application var obj = _uow.HomeSection2s.GetAll() like this, it won't fill the Detail.
What you mean is reffered to as 'Lazy Loading'. It would require you to make those properties virtual, like:
public virtual List<HomeSection2Detail> HomeSection2Detail { get; set; }
You can also take a look at this anwser
More documentation on loading related data
i am new to fluent nhibernate. i'm developing a project contains following 3 tables in its database:
"Person",
"RealPerson" and
"LegalPerson"
these three tables have relation as shown in picture:
all entities in my code such as these three entities are inherited from a base entity class here is the code of these entities
public class Person : Entity
{
public virtual RealPerson RealPerson { set; get; }
public virtual LegalPerson LegalPerson { set; get; }
}
public class RealPerson : Entity
{
public virtual string FirstName { set; get; }
public virtual string LastName { set; get; }
public virtual string FatherName { set; get; }
public virtual string NationalCode { set; get; }
public virtual DateTime BirthDate { set; get; }
public virtual string PhoneNumber { set; get; }
public virtual string MobileNumber { set; get; }
public virtual string EmailAddress { set; get; }
public virtual string HomeAddress { set; get; }
public virtual string WorkAddress { set; get; }
public virtual RealPerson Proxy { set; get; }
}
public class LegalPerson : Entity
{
public virtual string LegalPerson_Name { set; get; }
public virtual string RegistrationNumber { set; get; }
public virtual string Address { set; get; }
public virtual string PhoneNumber1 { set; get; }
public virtual string PhoneNumber2 { set; get; }
public virtual string PhoneNumber3 { set; get; }
public virtual RealPerson Proxy { set; get; }
}
and the code of base entity class is here:
public class Entity
{
protected bool Equals(Entity other)
{
if (other == null)
return false;
if (Id == Guid.Empty || other.Id == Guid.Empty)
return base.Equals(other);
return Id.Equals(other.Id);
}
public virtual Guid Id { set; get; }
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is Entity)
return Equals((Entity)obj);
return base.Equals(obj);
}
protected ISession Session
{
get { return SessionAccountant.GetSession(); }
}
public virtual void Save()
{
Session.SaveOrUpdate(this);
}
public virtual void Delete()
{
Session.Delete(this);
}
}
Finally the classmaps are as following:
public class PersonMapping : ClassMap<Person>
{
public PersonMapping()
{
Table("Person");
Id(x => x.Id).GeneratedBy.GuidComb().Column("Person_Id");
References(x => x.RealPerson).Nullable().LazyLoad().Column("RealPerson_Id");
References(x => x.LegalPerson).Nullable().LazyLoad().Column("LegalPerson_Id");
}
}
public class RealPersonMapping : ClassMap<RealPerson>
{
public RealPersonMapping()
{
Table("RealPerson");
Id(x => x.Id).GeneratedBy.GuidComb().Column("RealPerson_Id");
Map(x => x.FirstName).Not.Nullable().Column("FirstName");
Map(x => x.LastName).Not.Nullable().Column("LastName");
Map(x => x.FatherName).Not.Nullable().Column("FatherName");
Map(x => x.NationalCode).Not.Nullable().Column("NationalCode");
Map(x => x.BirthDate).Nullable().Column("BirthDate");
Map(x => x.ShenasnamehNumber).Nullable().Column("ShenasnamehNumber");
Map(x => x.PhoneNumber).Nullable().Column("PhoneNumber");
Map(x => x.MobileNumber).Nullable().Column("MobileNumber");
Map(x => x.EmailAddress).Nullable().Column("EmailAddress");
Map(x => x.HomeAddress).Nullable().Column("HomeAddress");
Map(x => x.WorkAddress).Nullable().Column("WorkAddress");
References(x => x.Proxy).Nullable().LazyLoad().Column("Proxy_Id");
}
}
public class LegalPersonMapping : ClassMap<LegalPerson>
{
public LegalPersonMapping()
{
Table("LegalPerson");
Id(x => x.Id).GeneratedBy.GuidComb().Column("LegalPerson_Id");
Map(x => x.LegalPerson_Name).Not.Nullable().Column("LegalPerson_Name");
Map(x => x.RegistrationNumber).Not.Nullable().Column("RegistrationNumber");
Map(x => x.Address).Not.Nullable().Column("Address");
Map(x => x.PhoneNumber1).Nullable().Column("PhoneNumber1");
Map(x => x.PhoneNumber2).Nullable().Column("PhoneNumber2");
Map(x => x.PhoneNumber3).Nullable().Column("PhoneNumber3");
References(x => x.Proxy).Nullable().LazyLoad().Column("Proxy_Id");
}
}
i set the configuration and create a session. but when i run the project i get this exception at run time:
An unhandled exception of type 'NHibernate.MappingException' occurred in NHibernate.dll
Additional information: Could not determine type for: EntitiesClasses.Person
what is wrong with this code?!
You need to inherit from SubclassMap.
See here http://notherdev.blogspot.com/2012/01/mapping-by-code-inheritance.html?m=1
I think this is going to change your schema in that your base class isn't going to have the id of the subclass. The id of the base class is the id of the subclass.
The more messages I read about it the more I get confused! Maybe I simply understand something wrong... I have two entities: Computer and OperatingSystem, both have a few dozens properties.
The relation I like to map is one-to-one, one computer has one OS. To shorten I only show relevant properties:
public abstract class EntityBase
{
public virtual Guid Id { get; set; }
public virtual DateTime CDate { get; set; }
public virtual string CUser { get; set; }
protected EntityBase()
{
Initialize();
}
private void Initialize()
{
CDate = DateTime.Now;
var wi = System.Security.Principal.WindowsIdentity.GetCurrent();
if (wi != null)
CUser = wi.Name;
}
}
public class ComputerDb : EntityBase
{
public virtual string ComputerType { get; set; }
public virtual string Domain { get; set; }
public virtual string Name { get; set; }
/* ...... */
public virtual OsDb Os { get; set; }
public virtual void AddOs(OsDb os)
{
this.Os = os;
}
public class ComputerDbMap : ClassMap<ComputerDb>
{
public ComputerDbMap()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.ComputerType).Nullable().Length(16);
Map(x => x.Domain).Nullable().Length(64);
Map(x => x.Name).Not.Nullable().Length(64);
/* .... */
HasOne(x => x.Os).Cascade.All().PropertyRef(x => x.Computer);
}
}
public class OsDb : EntityBase
{
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual bool? PartOfCluster { get; set; }
/* ... */
public virtual ComputerDb Computer { get; set; }
}
public class OsDbMap : ClassMap<OsDb>
{
public OsDbMap()
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.Name).Nullable().Length(128).Index("Idx_OsName");
Map(x => x.Description).Nullable().Length(128);
Map(x => x.PartOfCluster).Nullable();
/* .... */
References(x => x.Computer, "Computer_Id").Unique();
}
}
In the program I do:
var computer = getComputerDb(ps);
var os = getOsDb(ps);
computer.AddOs(os);
var o = new Operations();
o.AddComputerToDb(computer);
where
public void AddComputerToDb(ComputerDb cpDb)
{
using (var session = _sessionManager.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
try
{
session.SaveOrUpdate(cpDb);
transaction.Commit();
}
catch (Exception e)
{
Log.Error($"Exception in AddComputerToDb(). Exception: {e}");
transaction.Rollback();
throw;
}
finally
{
session.Close();
}
}
}
Here the result of the select on the tblComputerDb table on SQLServer:
And here the result from the tblOsDb table:
Problem: Computer_Id is NULL. If I understand things right, it should contain the GUID of the computer record 053DFFDF-0A88-4270-8405-A5EE00FFD388. I do not understand, why it cannot fill this Id from the computer entity. Modelling as ONE-TO-MANY works just fine, but is NOT what I want...
What am I doing wrong?
In my C# project, I get an error when EF attempts to create my database
The error occurs when I call
Database.SetInitializer(new CreateDatabaseIfNotExists<ApplicationDatabase>());
The error message is
The expression 'x => x.Dependancies' is not a valid property expression. The expression should represent a property: C#: 't => t.MyProperty' VB.Net: 'Function(t) t.MyProperty'.
My Domain classes are as follows
[Table("LoggedEntity")]
public class LoggedEntity
{
public int Id { get; set; }
}
[Table("TemplateTaskDependancy")]
public class TemplateTaskDependancy : LoggedEntity
{
[Column]
public int NeededTaskId { get; set; }
[Column]
public int TaskId { get; set; }
[Required]
[ForeignKey("TaskId")]
public virtual TemplateTask Task { get; set; }
[Required]
[ForeignKey("NeededTaskId")]
public virtual TemplateTask NeededTask { get; set; }
}
[Table("TemplateTask")]
public class TemplateTask : LoggedEntity
{
public ICollection<TemplateTaskDependancy> Dependancies;
public ICollection<TemplateTaskDependancy> NeededTasks;
public virtual Template Template { get; set; }
}
[Table("Template")]
public class Template : LoggedEntity
{
public string Description { get; set; }
}
My Configuration Class is as follows
public class TemplateTaskConfiguration : EntityTypeConfiguration<TemplateTask>
{
public TemplateTaskConfiguration()
{
HasMany(x => x.Dependancies)
.WithRequired(d => d.Task)
.HasForeignKey(d => d.TaskId)
.WillCascadeOnDelete(false);
HasMany(x => x.NeededTasks)
.WithRequired(d => d.NeededTask)
.HasForeignKey(d => d.NeededTaskId)
.WillCascadeOnDelete(false);
}
}
My Context is as follows
public class ApplicationDatabase : DbContext
{
public DbSet<TemplateTask> TemplateTasks { get; set; }
public DbSet<TemplateTaskDependancy> TemplateTaskDependancies { get; set; }
public DbSet<Template> Templates { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Configurations.Add(new TemplateTaskConfiguration());
}
public void InitializeDatabase()
{
Database.SetInitializer(new CreateDatabaseIfNotExists<ApplicationDatabase>());
}
}
Quite literally, the problem is what is described. Dependancies is a field, not a property. Just define it as:
public virtual ICollection<TemplateTaskDependancy> Dependancies
{
get;
set;
}
And it should solve your problem.