two class reference eachother , how to do Not.LazyLoad in fluent nhibernate - fluent-nhibernate

i have two class
public class ProInfo
{
public ProInfo()
{
ProPrices = new List<ProPrice>();
}
public virtual Guid ProID { get; set; }
public virtual string ProCate { get; set; }
public virtual string Name { get; set; }
public virtual string Unit { get; set; }
public virtual string PicName { get; set; }
public virtual string Memo { get; set; }
public virtual bool DeleteFlag { get; set; }
public virtual DateTime LastUpDateTime { get; set; }
public virtual IList<ProPrice> ProPrices { get; set; }
}
public class ProPrice
{
public virtual int Id { get; set; }
public virtual AreaInfo AreaInfo { get; set; }
public virtual ProInfo ProInfo { get; set; }
public virtual Decimal Price { get; set; }
}
mapping codes are :
public ProInfoMap()
{
Id(x => x.ProID);
Map(x => x.DeleteFlag);
Map(x => x.Name);
Map(x => x.PicName);
Map(x => x.ProCate);
Map(x => x.Unit);
Map(x => x.LastUpDateTime);
HasMany<ProPrice>(x => x.ProPrices);
}
public ProPriceMap()
{
Id(x => x.Id);
Map(x => x.Price);
References<ProInfo> (x => x.ProInfo);
References<AreaInfo>(x => x.AreaInfo);
}
what i want is to disable the proprices's lazyload(), so i can get all the prices for the product from database. but, when i change the onetomany to this: HasMany<ProPrice>(x => x.ProPrices).Not.LazyLoad(), it cause an Infinite loop. what do i miss?

I don't know, where exactly the loop comes from, but your bidirectional association may cause this. You should declare one side as Inverse(). This can only be done in ProInfoMap, because it is a one-to-many relationship with a bidirectional association:
HasMany<ProPrice>(x => x.ProPrices).Inverse().Not.LazyLoad();
Try that. It may remove the infinite loop.

Related

Many to Many Nhibernate - Duplicate records and no insert

I have three tables in a many to many relationship with the nhibernate maps below. My objects are also below. A portfolio item can have many tags. The problem I am having is
1) update save another tag even when the name is the same as last time. So duplicate records get inserted into tag when the tag is the same. So for example if the tag for one portfolio object was abc the next portfolio item that adds the tag should reference this record rather than reinserting abc. I think this is because of the id column in the tag map. Nhibernate needs an id though.
2) Create does not add records in the join table. Records in the join table are only added on updates.
Domain Objects
public class Portfolio {
public Portfolio() {
PortfolioImage = new List<Portfolioimage>();
Tag = new List<Tag>();
}
public virtual int PortfolioId { get; set; }
public virtual string AliasTitle { get; set; }
public virtual string MetaDescription { get; set; }
public virtual string Title { get; set; }
public virtual string Client { get; set; }
public virtual string Summary { get; set; }
public virtual string Url { get; set; }
public virtual string MainImage { get; set; }
public virtual string TitleAlt { get; set; }
public virtual string Description { get; set; }
public virtual IList<Portfolioimage> PortfolioImage { get; set; }
public virtual IList<Tag> Tag { get; set; }
}
public class Portfoliotag {
public virtual int Id { get; set; }
public virtual Portfolio Portfolio { get; set; }
public virtual Tag Tag { get; set; }
}
public class Tag {
public Tag() {
Portfolio = new List<Portfolio>();
}
public virtual int TagId { get; set; }
public virtual string TagVal { get; set; }
public virtual IList<Portfolio> Portfolio { get; set; }
}
Maps
public class PortfolioMap : ClassMap<Portfolio> {
public PortfolioMap() {
Table("Portfolio");
LazyLoad();
Id(x => x.PortfolioId).GeneratedBy.Identity().Column("PortfolioId");
Map(x => x.AliasTitle).Column("AliasTitle").Not.Nullable();
Map(x => x.MetaDescription).Column("MetaDescription").Not.Nullable();
Map(x => x.Title).Column("Title").Not.Nullable();
Map(x => x.Client).Column("Client").Not.Nullable();
Map(x => x.Summary).Column("Summary").Not.Nullable();
Map(x => x.Url).Column("Url");
Map(x => x.MainImage).Column("MainImage");
Map(x => x.TitleAlt).Column("TitleAlt");
Map(x => x.Description).Column("Description").Not.Nullable();
HasMany(x => x.PortfolioImage).KeyColumn("PortfolioId").Inverse();
HasManyToMany(x => x.Tag).Table("PortfolioTag").ParentKeyColumn("PortfolioId").ChildKeyColumn("TagId").LazyLoad().Cascade.All().Fetch.Join();
}
}
public class PortfoliotagMap : ClassMap<Portfoliotag> {
public PortfoliotagMap() {
Table("PortfolioTag");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("Id");
References(x => x.Portfolio).Not.Nullable().Cascade.SaveUpdate().Column("PortfolioId");
References(x => x.Tag).Not.Nullable().Cascade.SaveUpdate().Column("TagId");
}
}
public class TagMap : ClassMap<Tag> {
public TagMap() {
Table("Tag");
LazyLoad();
Id(x => x.TagId).GeneratedBy.Identity().Column("TagId");
Map(x => x.TagVal).Column("Tag").Not.Nullable();
//HasMany(x => x.PortfolioTag).KeyColumn("TagId");
// HasMany(x => x.PortfolioTag).Cascade.AllDeleteOrphan().Inverse().Fetch.Join().KeyColumn("TagId");
HasManyToMany(x => x.Portfolio).Table("PortfolioTag").ParentKeyColumn("PortfolioId").ChildKeyColumn("TagId").LazyLoad().Inverse().Cascade.AllDeleteOrphan();
}
}
given the classes
public class Portfolio
{
public Portfolio()
{
Tag = new List<Tag>();
}
public virtual int PortfolioId { get; protected set; }
public virtual IList<Tag> Tag { get; protected set; }
}
public class Tag
{
public virtual int TagId { get; set; }
public virtual string Name { get; set; }
}
the this mapping should suffice
public class PortfolioMap : ClassMap<Portfolio>
{
public PortfolioMap()
{
Id(x => x.PortfolioId).GeneratedBy.Identity().Column("PortfolioId");
HasManyToMany(x => x.Tag)
.Table("PortfolioTag")
.ParentKeyColumn("PortfolioId")
.ChildKeyColumn("TagId")
.Cascade.All()
.Fetch.Join();
}
}
assigning existing tags has to be handled in code which can cache or query involved tags more efficiently than automatic querying by any framework.
Update:
example usage which works for me
public void Save(int portfolioId, IEnumerable<string> tagnames)
{
using (var tx = session.BeginTransaction())
{
var tags = Session.QueryOver<Tag>().WhereProperty(x => x.Name).In(tagnames).List();
var portfolio = session.Get<Portfolio>(portfolioId);
portfolio.Tags.Clear();
portfolio.Tags.AddRange(tags);
tx.Commit();
}
}

Nhibernate SubClass relationship generating wrong SQL

I'm using Table Per Type(TPT) to do inheritance in Nhibernate v3.3.1.4000. I figured out that any SQL for SubClass relationships one-to-many are wrong.
Class:
public class Repasse : Colaboracao
{
public virtual string Descricao { get; set; }
public virtual Decimal ValorRepasse { get; set; }
public virtual DateTime DataInicio { get; set; }
public virtual DateTime DataTermino { get; set; }
[XmlIgnore]
public virtual Usuario UsuarioExecucao { get; set; }
[XmlIgnore]
public virtual Usuario UsuarioMonitoramento { get; set; }
[XmlIgnore]
public virtual IList<RepasseRecebido> RepassesRecebidos { get; set; }
[XmlIgnore]
public virtual IList<RepasseProduto> Produtos { get; set; }
public Repasse()
{
RepassesRecebidos = new List<RepasseRecebido>();
Produtos = new List<RepasseProduto>();
UsuarioExecucao = new Usuario();
UsuarioMonitoramento = new Usuario();
}
}
public class RepasseRecebido : Entidade
{
public virtual string NumNotaAtorizacao { get; set; }
public virtual Decimal ValorTaxaCambio { get; set; }
public virtual DateTime DataRecebimento { get; set; }
public virtual Decimal ValorRecebido { get; set; }
public virtual string Observacao { get; set; }
[XmlIgnore]
public virtual Repasse Repasse { get; set; }
[XmlIgnore]
public virtual List<Download> Downloads { get; set; }
public RepasseRecebido()
{
Repasse = new Repasse();
Downloads = new List<Download>();
}
}
public class RepasseProduto : Entidade
{
public virtual int QtdProduto { get; set; }
public virtual DateTime DataInicio { get; set; }
public virtual DateTime DataTermino { get; set; }
public virtual int QtdBeneficiado { get; set; }
public virtual PublicoBeneficiado PublicoBeneficiado { get; set; }
[XmlIgnore]
public virtual Produto Produto { get; set; }
[XmlIgnore]
public virtual Repasse Repasse { get; set; }
[XmlIgnore]
public virtual IList<RepasseProdutoAtividade> Atividades { get; set; }
public RepasseProduto()
{
Produto = new Produto();
Repasse = new Repasse();
Atividades = new List<RepasseProdutoAtividade>();
}
}
public class RepasseProdutoAtividade : Entidade
{
public virtual DateTime DataInicio { get; set; }
public virtual DateTime DataTermino { get; set; }
public virtual string Descricao { get; set; }
[XmlIgnore]
public virtual RepasseProduto RepasseProduto { get; set; }
public RepasseProdutoAtividade()
{
RepasseProduto = new RepasseProduto();
}
}
Map:
public class RepasseMap : SubclassMap<Repasse>
{
public RepasseMap()
{
Schema(ConfigInstances.ObterSchema("Sigma"));
Table("tblRepasse");
LazyLoad();
KeyColumn("cmpIdRepasse");
Map(x => x.Descricao).Column("cmpDcDescricao");
Map(x => x.ValorRepasse).Column("cmpVlValorRepasse").Not.Nullable();
Map(x => x.DataInicio).Column("cmpDtDataInicio").Not.Nullable();
Map(x => x.DataTermino).Column("cmpDtDataTermino").Not.Nullable();
References(x => x.UsuarioExecucao).Column("cmpIdUsuarioExecucao");
References(x => x.UsuarioMonitoramento).Column("cmpIdUsuarioMonitoramento");
HasMany(x => x.RepassesRecebidos).AsBag().LazyLoad();
HasMany(x => x.Produtos).KeyColumn("cmpIdRepasseProduto").AsBag().LazyLoad();
}
public class RepasseRecebidoMap : ClassMap<RepasseRecebido>
{
public RepasseRecebidoMap()
{
Schema(ConfigInstances.ObterSchema("Sigma"));
Table("tblRecursoRepasse");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("cmpIdRecursoRepasse");
Map(x => x.NumNotaAtorizacao).Column("cmpNuAutorizacaoNota").Not.Nullable();
Map(x => x.DataRecebimento).Column("cmpDtDataRecebimento").Not.Nullable();
Map(x => x.ValorRecebido).Column("cmpVlValorRecebido").Not.Nullable();
Map(x => x.ValorTaxaCambio).Column("cmpVlTaxaCambio").Not.Nullable();
Map(x => x.Observacao).Column("cmpDcObservacao");
References(x => x.Repasse).Column("cmpIdRepasse");
HasManyToMany(x => x.Downloads)
.Table("tblRecursoRepasseDownload")
.ParentKeyColumn("cmpIdRecursoRepasse")
.ChildKeyColumn("cmpIdDownload")
.AsBag().LazyLoad().Cascade.SaveUpdate();
}
}
public class RepasseProdutoMap : ClassMap<RepasseProduto>
{
public RepasseProdutoMap()
{
Schema(ConfigInstances.ObterSchema("Sigma"));
Table("tblRepasseProduto");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("cmpIdRepasseProduto");
Map(x => x.DataInicio).Column("cmpDtDatainicio").Not.Nullable();
Map(x => x.DataTermino).Column("cmpDtDatatermino").Not.Nullable();
Map(x => x.QtdProduto).Column("cmpInQuantidadeproduto").Not.Nullable();
Map(x => x.QtdBeneficiado).Column("cmpIdQuantidadeBeneficiado").Not.Nullable();
Map(x => x.PublicoBeneficiado).Column("cmpIdPublicoBeneficiado").CustomType(typeof(PublicoBeneficiado));
References(x => x.Produto).Column("cmpIdProduto");
References(x => x.Repasse).Column("cmpIdRepasse");
HasMany(x => x.Atividades).AsBag().LazyLoad();
}
}
public class RepasseProdutoAtividadeMap : ClassMap<RepasseProdutoAtividade>
{
public RepasseProdutoAtividadeMap()
{
Schema(ConfigInstances.ObterSchema("Sigma"));
Table("tblRepasseProdutoAtividade");
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity().Column("cmpIdRepasseProdutoAtividade");
Map(x => x.DataInicio).Column("cmpDtInicio").Not.Nullable();
Map(x => x.DataTermino).Column("cmpDtTermino").Not.Nullable();
Map(x => x.Descricao).Column("cmpDcAtividade").Not.Nullable();
References(x => x.RepasseProduto).Column("cmpIdRepasseProduto");
}
}
}
When I query RepasseProduto then SQL is generated with an issue, the query doesn't findout how to get the Foreign Key name for the one-to-many relationship, as you can see below:
select repasse0_.cmpIdRepasse as cmpIdCol1_5_
repasse0_1_.cmpDtDataCriacao as cmpDtDat2_5_
repasse0_1_.cmpStSituacao as cmpStSit3_5_
repasse0_1_.cmpDcCancelamento as cmpDcCan4_5_
repasse0_1_.cmpIdRecurso as cmpIdRec5_5_
repasse0_.cmpDcDescricao as cmpDcDes2_7_
repasse0_.cmpVlValorRepasse as cmpVlVal3_7_
repasse0_.cmpDtDataInicio as cmpDtDat4_7_
repasse0_.cmpDtDataTermino as cmpDtDat5_7_
repasse0_.cmpIdUsuarioExecucao as cmpIdUsu6_7_
repasse0_.cmpIdUsuarioMonitoramento as cmpIdUsu7_7_
from mre_sigma_dsv.dbo.tblRepasse repasse0_
inner join mre_sigma_dsv.dbo.tblColaboracao repasse0_1_
on repasse0_.cmpIdRepasse=repasse0_1_.cmpIdColaboracao
where (select cast(count(*) as INT)
from mre_sigma_dsv.dbo.tblRepasseProduto produtos1_
where repasse0_.cmpIdRepasse=produtos1_.Repasse_id)>#p0
As you can see the last inner select doesn't find out the name of the foreign key from tblRepasseProduto to tblRepasse, then uses Repasse_id that doesn't represent a valid table field.
What should I do? Am I missing something when mapping my sub-class relation?
Really not sure from where the ghost column comes, but there is other issue in the mapping above. In relations one-to-many vs many-to-one, i.e. in fluent HasMany vs References, there must be/is exactly one column representing that. So we need to use the same (one) column for that and should change the mapping this way.
The RepasseMap : SubclassMap<Repasse>:
public RepasseMap()
{ ...
// was:
// HasMany(x => x.RepassesRecebidos).AsBag().LazyLoad();
// HasMany(x => x.Produtos).KeyColumn("cmpIdRepasseProduto").AsBag().LazyLoad();
// should be
HasMany(x => x.RepassesRecebidos)
.KeyColumn("cmpIdRepasse").AsBag().LazyLoad();
HasMany(x => x.Produtos)
.KeyColumn("cmpIdRepasse").AsBag().LazyLoad();
}
The RepasseRecebidoMap : ClassMap<RepasseRecebido>:
public RepasseRecebidoMap()
{ ...
// the same column representing this relationship in table "tblRecursoRepasse"
References(x => x.Repasse).Column("cmpIdRepasse");
The RepasseProdutoMap : ClassMap<RepasseProduto>:
public RepasseProdutoMap()
{ ...
// the same column representing this relationship in table "tblRepasseProduto"
References(x => x.Repasse).Column("cmpIdRepasse");
If this does not help, could you please send the query you've used and which generated that strange relationship.
Also, in the Mapping snippet above you are nesting the mapping classes ... this is not the right/required way.

FluentNhibernate .CheckReference is failing

public class WorldEntity
{
public WorldEntity()
{
Scenes = new List<SceneEntity>();
}
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Picture { get; set; }
public virtual IList<SceneEntity> Scenes { get; set; }
}
public class WorldMap : ClassMap<WorldEntity>
{
public WorldMap()
{
Table("Worlds");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
Map(x => x.Picture);
HasMany(x => x.Scenes).KeyColumn("Id");
}
}
public class SceneEntity
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual string Image { get; set; }
//public virtual int WorldId { get; set; }
public virtual WorldEntity World { get; set; }
public virtual short NoExits { get; set; }
public virtual string AnimatedIntroPath { get; set; }
}
public class SceneMap: ClassMap<SceneEntity>
{
public SceneMap()
{
Table("Scenes");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
Map(x => x.Image);
Map(x => x.NoExits);
Map(x => x.AnimatedIntroPath);
//Map(x => x.WorldId).Not.Nullable();
References(wrd => wrd.World, "WorldId");
}
}
[Test]
new PersistenceSpecification<SceneEntity>(Session)
.CheckProperty(x => x.Name, "Scene Name")
.CheckProperty(x => x.Image, "path to image")
//.CheckProperty(x=>x.WorldId,aa.Id)
.CheckReference(x => x.World,aa )
.VerifyTheMappings();
after running the test I am getting this error:
System.ApplicationException : For property 'World' expected same element, but got different element of type 'TwitQuestNet.DataDefinitions.OrmConfig.Entities.WorldEntity'.
Tip: override ToString() on the type to find out the difference.
at FluentNHibernate.Testing.Values.Property2.CheckValue(Object target)
at System.Collections.Generic.List1.ForEach(Action1 action)
at FluentNHibernate.Testing.PersistenceSpecification1.VerifyTheMappings(T first)
at TwitQuestNet.Test.EntityMapTests.SceneTest.scene_map_succsess() in SceneTest.cs: line 23
what I am doing wrong here ? as I am stuck for nearly a day :(
Sorted. I had to add EqualityComparer() the the test will pass

creating in query in nhibernate using linq

i want to create something like
SELECT * FROM dbo.localconveyance_details WHERE
voucherNo IN (SELECT voucherNo FROM dbo.localconveyance_master WHERE emp_code = '48'
using linq in fluent nhibernate
tried something like this
IList<LocalConveyanceDetails> detailslist = session.Query<LocalConveyanceDetails>()
.Where(x => x.LocalConveyanceMaster.emp_code == e_id).ToList();
but its not working ... can someone tell what would be the actual query ?
Update :
the Entities which i have used are :
public class LocalConveyanceMaster
{
public virtual String voucherNo { get; set; }
public virtual DateTime voucher_date { get; set; }
public virtual String emp_code { get; set; }
public virtual String emp_name { get; set; }
public virtual String project_id { get; set; }
public virtual DateTime submitDate { get; set; }
public virtual String to_be_approved_by { get; set; }
public virtual String created_by { get; set; }
public virtual Decimal conveyance_total { get; set; }
public virtual Decimal approved_amount { get; set; }
public virtual String approved { get; set; }
public virtual ProjectMaster Project { get; set; }
public virtual ICollection<LocalConveyanceDetails> LocalConveyanceDetails { get; set; }
}
public class LocalConveyanceDetails
{
public virtual String LcDetailsId { get; set; }
public virtual String voucherNo { get; set; }
public virtual String serialNo { get; set; }
public virtual String From_Project_Id { get; set; }
public virtual String To_Project_Id { get; set; }
public virtual DateTime particularsDate { get; set; }
public virtual Decimal particularsAmount { get; set; }
public virtual String particulars { get; set; }
public virtual LocalConveyanceMaster LocalConveyanceMaster { get; set; }
}
and the mappings are :
public LocalConveyanceMap()
{
Table("localconveyance_master");
Id(x => x.voucherNo).Column("voucherNo");
Map(x => x.voucher_date);
Map(x => x.emp_code);
Map(x => x.emp_name);
Map(x => x.project_id);
Map(x => x.submitDate);
Map(x => x.to_be_approved_by);
Map(x => x.created_by);
Map(x => x.conveyance_total);
Map(x => x.approved_amount);
Map(x => x.approved);
References(x => x.Project)
.Column("project_id")
.ForeignKey("project_id");
HasMany(x => x.LocalConveyanceDetails)
.KeyColumn("voucherno").AsSet();
}
public LocalConveyanceDetailsMap()
{
Table("Localconveyance_details");
Id(x => x.LcDetailsId).Column("LcDetailsId");
Map(x => x.voucherNo);
Map(x => x.serialNo);
Map(x => x.From_Project_Id);
Map(x => x.To_Project_Id);
Map(x => x.particularsDate);
Map(x => x.particularsAmount);
Map(x => x.particulars);
References(x => x.LocalConveyanceMaster)
.PropertyRef(x => x.voucherNo).Column("voucherno")
.ForeignKey("voucherno");
}
the error which i am getting is :
Exception : {"Error performing LoadByUniqueKey[SQL: SQL not available]"}
InnerException : {"The given key was not present in the dictionary."}
that's occurred when the one or more member of class is kind of other class [relationship].
i have a same problem and i remove that members and add new member for each of them in this form :
public virtual int? [related class]id {get;set;}
exmaple :
public virtual int? PersonId {get;set;}

How am I supposed to query for a persisted object's property's subproperty in nhibernate?

I'm feeling dumb.
public class Uber
{
public Foo Foo { get; set; }
public Bar Bar { get; set; }
}
public class Foo
{
public string Name { get; set; }
}
...
var ubercharged = session.CreateCriteria(typeof(Uber))
.Add(Expression.Eq("Foo.Name", "somename"))
.UniqueResult<Uber>();
return ubercharged;
This throws a "could not resolve property" error.
What am I doing wrong? I want to query for an Uber object that has a property Foo which has a Name of "somename".
updated with real life example, repository call, using fluent nhibernate:
public UserPersonalization GetUserPersonalization(string username)
{
ISession session = _sessionSource.GetSession();
var personuser = session.CreateCriteria(typeof(UserPersonalization))
.Add(Expression.Eq("User.Username", username))
.UniqueResult<UserPersonalization>();
return personuser;
}
The classes/mappings:
public class User
{
public virtual Guid UserId { get; set; }
public virtual string Username { get; set; }
public virtual string Email { get; set; }
public virtual string PasswordHash { get; set; }
public virtual string PasswordSalt { get; set; }
public virtual bool IsLockedOut { get; set; }
public virtual bool IsApproved { get; set; }
}
public class Person
{
public virtual int PersonId { get; set; }
public virtual string Name { get; set; }
public virtual Company Company { get; set; }
}
public class UserPersonalization
{
public virtual int UserPersonalizationId { get; set; }
public virtual Person Person { get; set; }
public virtual User User { get; set; }
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.UserId).GeneratedBy.Guid().ColumnName("UserId");
Map(x => x.Username);
Map(x => x.PasswordHash);
Map(x => x.PasswordSalt);
Map(x => x.Email);
Map(x => x.IsApproved);
Map(x => x.IsLockedOut);
}
}
public class UserPersonalizationMap : ClassMap<UserPersonalization>
{
public UserPersonalizationMap()
{
WithTable("UserPersonalization");
Id(x => x.UserPersonalizationId).ColumnName("UserPersonalizationId");
References(x => x.Person).ColumnName("PersonId");
References(x => x.User).ColumnName("UserId");
}
}
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.PersonId).ColumnName("PersonId");
Map(x => x.Name);
References(x => x.Company).ColumnName("CompanyId");
}
}
Try this:
var ubercharged = session.CreateCriteria(typeof(Uber))
.CreateCriteria("Foo")
.Add(Restrictions.Eq("Name", "somename"))
.UniqueResult<Uber>();
Can you sort using "ubercharged.AddOrder(Order.asc("Foo.Name")) syntax? This syntax should work in NHib 2.01. If not, your maps are not working correctly.
Stuart's answer should work fine for you though.