Error saving components to database with fluent nHibernate? - c#

Here is my object and mapping:
public class candleStim
{
public virtual int Id { get; set; }
public virtual int candleNumber { get; set; } //the number of the candle from the data set, should correspond with number of minutes into testing on 1 min candles
public virtual DateTime date { get; set; }
public virtual decimal open { get; set; }
public virtual decimal high { get; set; }
public virtual decimal low { get; set; }
public virtual decimal close { get; set; }
public virtual List<EMA> EMAs { get; set; } //List all EMAs calculated.
public virtual List<SMA> SMAs { get; set; }
}
public class candleStimMap : ClassMap<candleStim>
{
public candleStimMap()
{
Id(x => x.Id);
Map(x => x.candleNumber);
Map(x => x.date);
Map(x => x.open);
Map(x => x.high);
Map(x => x.low);
Map(x => x.close);
HasMany<SMA>(x => x.SMAs)
.Component(c =>
{
c.Map(x => x.SimpleMovingAverage);
c.Map(x => x.periods);
}).AsSet();
HasMany<EMA>(x => x.EMAs)
.Component(c =>
{
c.Map(x => x.ExponentialMovingAverage);
c.Map(x => x.periods);
}).AsSet();
Table("candle_Simulation");
} //end public candleStimMap()
Here is my current attempt at saving (which fails)
foreach (candleStim c in calculatedCandles)
{
using (var session = NHibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
candleStim cc = new candleStim();
cc.date = c.date;
cc.open = c.open;
cc.high = c.high;
cc.low = c.low;
cc.close = c.close;
//The below 2 lines are where the problem arises
//if these are standard objects, no errors show up
cc.EMAs = c.EMAs;
cc.SMAs = c.SMAs;
session.Save(c);
transaction.Commit();
}
}
counter++;
}
The error msg:{"Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericSet1[Midas_FOREX_Engine.Indicators.SMA]' to type 'System.Collections.Generic.List1[Midas_FOREX_Engine.Indicators.SMA]'."}
So I've got a mismatch of list types. How would I make a list of the NHibernate.Collection.Generic.PersistentGenericSet type and save the values?
The only fields Im saving to the database from the SMA-EMA is a decimal of the value and an integer of the number of periods.
Thank you!!

When you map a HasMany property to AsSet, you should use an ISet type on it.
So you property will become like:
public virtual Iesi.Collections.ISet<EMA> EMAs { get; set; }
I strongly recommend you to read this NHibernate docs chapter (if you still didn't).
http://nhibernate.info/doc/nh/en/index.html#collections-persistent
It will clarify you about how to choose the best property type / mapping to your one-to-many situation.

Related

Select many over complex model and multiple collections

I am trying to flatten out my model and I am coming across an issue I can't seem to understand.
Inspection Item Model:
public class InspectionItem
{
public string InspectionItemName { get; set; }
public ICollection<Inspection> Inspections { get; set; }
}
Inspection Model:
public class Inspection
{
public InspectionItem InspectionItem { get; set; }
public string InspectionItemId { get; set; }
public string PassFail { get; set; }
public ICollection<Answer> Answers { get; set; }
public ICollection<InspectionInputAnswer> InspectionInputAnswers { get; set; }
}
The Query:
So my issue is, if an Inspection does not contain a data for BOTH Answers and InspectionInputAnswers, the whole list returns 0 records? If the Inspection contains a record for both it then returns data. I don't understand why my select many clause is working this way? I am trying to flatten Inspections and both Answers/InspectionInputAnswers.
var inspectionItemInspections = await context.InspectionItems
.Include("Inspections")
.Include("Inspections.Answers")
.Include("Inspections.InspectionInputAnswers")
.Where(a => a.InspectionItemTypeId == idFilter)
.SelectMany(x => x.Inspections
.SelectMany(y => y.Answers
.SelectMany(z => y.InspectionInputAnswers,(answer,inputAnswer) => new { answer, inputAnswer })
.Select(d => new {
Date = y.CreatedAt,
InspectionItemName = x.InspectionItemName,
InspectionItemTypeId = x.InspectionItemTypeId,
InspectedById = y.InspectedById,
PassFail = y.PassFail,
QuestionId = d.answer.QuestionId,
ValueMeasured = d.inputAnswer.ValueMeasured
})
)).ToListAsync();
So how can I write this so that the Inspections relationship does not require an entry for both Answers and InspectionInputAnswers?
Thanks!

Error when using Select() instead of Include() in a query

I have the following query:
var catInclude = _db.Cat
.Where(x => x.ProvId == request.ProvId)
.Include(x => x.CatItems)
.SingleOrDefault(p => p.Id == request.ProvId
cancellationToken: cancellationToken);
As I don't want to get all properties from CatItems with Include(), I have created the following query:
var catSelect = _db.Cat
.Where(x => x.ProvId == request.ProvId)
.Select(p ==> new
{ Provider = p,
Items = p.CatItems.Select(x => new List<CatItems> { new CatItems
{ Id = x.Id, Name = x.Name, Price = x.Price } }
})})
SingleOrDefault(cancellationToken: cancellationToken);
But something is wrong in the 2nd query because here return _mapper.ProjectTo<CatDto>(cat) I get the following error:
Argument 1: cannot convert from '<anonymous type: Db.Entities.Cat Prov, System.Colletions.Generic.IEnumerable<System.Colletions.Generic.List<Models.CatItems> > Items>' to 'System.Linq.IQueryable'
Here is my CatDto:
public class CatDto
{
public int ProvId { get; set; }
public List<CatItems> CatItems { get; set; }
}
Here are my entities:
public class Prov
{
public int Id { get; set; }
public Cat Cat { get; set; }
}
public class Cat
{
public int Id { get; set; }
public int ProvId { get; set; }
public List<CatItems> CatItems { get; set; }
}
public class CatItems
{
public int Id { get; set; }
public int CatId { get; set; }
public DateTime CreatedOn { get; set; }
}
Is there a way to recreate the 2nd query and use it?
Main difference that instead of returning List of CatItems, your code returns IEnumerable<List<CatItems>> for property Items.
So, just correct your query to project to List:
var catSelect = await _db.Cat
.Where(x => x.ProvId == request.ProvId)
.Select(p => new CatDto
{
ProvId = p.ProvId,
Items = p.CatItems.Select(x => new CatItems
{
Id = x.Id,
Name = x.Name,
Price = x.Price
})
.ToList()
})
.SingleOrDefaultAsync(cancellationToken: cancellationToken);
I mean, even the exception is pretty self-explanatory. Nevertheless:
You are performing a .Select(...). It returns an Anonymous type. So, your catSelect is an anonymous type, thus the AutoMapper fails.
The quickest fix is to just cast (Cat)catSelect before mapping.
Or, you can dig deeper into how does AutoMapper play with anonymous types.
I feel like you can make most of the classes inherent Id and why is public cat CAT {get; set;} i thought you were supposed to initialize some kind of value

entityframework core - many to many - The property expression is not valid

Application Version:
Asp Net Core 1.1
EF: Microsoft.EntityFrameworkCore (1.1.1)
Line:
_dbContext.MyTable1.Include(c => c.MyIntermediateTable).ThenInclude(k => k.Select(x => x.MyTable2)).ToList();
Exception:
The property expression 'k => {from MyIntermediateTable x in k select
[x].MyTable2}' is not valid. The expression should represent a
property access: 't => t.MyProperty'. For more information on
including related data
My Entities
[Table("MyTable1")]
public class MyTable1
{
public MyTable1()
{
MyIntermediateTable = new List<MyIntermediateTable>();
}
[Column("MyPK1")]
public int MyPK1 { get; set; }
public string Name{ get; set; }
public virtual List<MyIntermediateTable> MyIntermediateTable{ get; set; }
}
[Table("MyIntermediateTable")]
public class MyIntermediateTable
{
public int MyPK1 { get; set; }
public int MyPK2 { get; set; }
public virtual MyTable1 MyTable1 { get; set; }
public virtual MyTable2 MyTable2 { get; set; }
}
[Table("MyTable2")]
public class MyTable2
{
public MyTable2()
{
MyIntermediateTable = new List<MyIntermediateTable>();
}
[Column("MyPK2")]
public int MyPK2 { get; set; }
public string Name{ get; set; }
public virtual List<MyIntermediateTable> MyIntermediateTable{ get; set; }
}
Model Builder (Fluent API)
modelBuilder.Entity<MyIntermediateTable>((item) =>
{
item.HasKey(p => new { p.MyPK1, p.MyPK2 });
item.HasOne(u => u.MyTable1).WithMany(u => u.MyIntermediateTable).HasForeignKey(u => u.MyPK1);
item.HasOne(u => u.MyTable2).WithMany(u => u.MyIntermediateTable).HasForeignKey(u => u.MyPK2);
});
modelBuilder.Entity<MyTable1>((item) =>
{
item.HasKey(p => p.MyPK1);
item.HasMany(u => u.MyIntermediateTable).WithOne(u => u.MyTable1).HasForeignKey(u => u.MyPK1);
});
modelBuilder.Entity<MyTable2>((item) =>
{
item.HasKey(p => p.MyPK2);
item.HasMany(u => u.MyIntermediateTable).WithOne(u => u.MyTable2).HasForeignKey(u => u.MyPK2);
});
The Intellisense in Visual Studio will only show you the list properties when doing auto-competition.
It's a bug (or something the Intellisense can't handle at the time of the writing) which happens when there are two overloads which match the signature: one for T other for IEnumerable<T>.
When this case appears, then just type .ThenInclude(m => m.MyProperty) even if the intellisense won't show you MyProperty, ignoring any errors the IDE shows you.
Once you close the method brackets, the error will disappear.
Extra information
This bug is tracked by this GitHub Issue Completion missing members of lambda parameter in fault tolerance case on the dotnet roslyn GitHub repository.

To show the very large data on the ui grid

public List<PropertyListDto> GetPropertiesByStatus(GetPropertyInput input)
{
//exception occurs here
var properties = _propertyRepository
.GetAll()
.Include(p => p.Address)
.ToList();
var results = new List<PropertyListDto>(properties.OrderBy(p => p.Id).MapTo<List<PropertyListDto>>());
return results;
}
[AutoMapFrom(typeof(Property))]
public class PropertyListDto : FullAuditedEntityDto
{
public new int Id { get; set; }
public CountyListDto County { get; set; }
public string Priority { get; set; }
public string Dist { get; set; }
public decimal ListingPrice { get; set; }
public string Blk { get; set; }
public AddressDto Address { get; set; }
public string Contact { get; set; }
public string Lot { get; set; }
public decimal Taxes { get; set; }
public string Mls { get; set; }
public ICollection<CommentEditDto> Comments { get; set; }
public int? LegacyId { get; set; }
}
Q : I need to show around 100,000 (1 lakh) data on the Angular UI Grid.But the problem is, above query gives memory exception.So could you tell me how to sort out this issue ? Thanks.
Note : I need to show the data without pagination.So I have selected this UI Grid.
UPDATE :
When I use .AsNoTracking(), then it works fine on the first query.
var properties = _propertyRepository
.GetAll()
.AsNoTracking()
.Include(p => p.Address)
.ToList();
But then the problem is on MapTo line.Could you tell me how to sort it out ? Thanks.
var results = new List<PropertyListDto>(properties.OrderBy(p => p.Id).MapTo<List<PropertyListDto>>());//error is here now
This is the error :
{"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."}
Mapping types:
Property_A048C3D093990BB6A086B710BAC90CB35FD4BAB180FC02FA3E90053FE58F20D3 -> ICollection`1
System.Data.Entity.DynamicProxies.Property_A048C3D093990BB6A086B710BAC90CB35FD4BAB180FC02FA3E90053FE58F20D3 -> System.Collections.Generic.ICollection`1[[IP.Comments.Dtos.CommentEditDto,IP.Application, Version=1.7.1.1, Culture=neutral, PublicKeyToken=null]]
Destination path:
List`1[3126].Comments3126[3126].Comments3126[3126]
Source value:
[Property_A048C3D093990BB6A086B710BAC90CB35FD4BAB180FC02FA3E90053FE58F20D3 3166]
UPDATE 2 : Here I have used Automapper to map EF object into Dto object.
I suppose you are initiate two ToList methods since I do not know what MapTo doing.
However instead doing mapping select directly your dto:
var properties = _propertyRepository
.GetAll()
.AsNoTracking()
.Include(p => p.Address).
.Select(s=> new PropertyListDto{
Id = s.Id
CountyListDto = s.CountyListDto
...
})
OP's Answer : Actually I have reduced all the unnecessary data on the above table and now it's having around 1K+ records.So no problem at all now.Cheers :)

NHibernate 3.3: Setting the type to Ansistring in an Id for Mapping by code

I am mapping the following entity as such:
public class PersonEntity
{
public virtual string PersonId { get; set; }
public virtual String Salutation { get; set; }
public virtual String FirstName { get; set; }
public virtual String LastName { get; set; }
public virtual DateTime Birthdate { get; set; }
}
public class PersonMap : ClassMapping<PersonEntity>
{
public PersonMap()
{
//ComponentAsId(i => i.Key, map => map.Property(p => p.PersonId, m => m.Type(NHibernateUtil.AnsiString)));
Id(i => i.PersonId, map => map.Type(???)));
Property(i => i.Salutation);
Property(i => i.FirstName);
Property(i => i.LastName);
Property(i => i.Birthdate);
}
}
As you can see in the commented out code, I can use the NHibernateUtil to set the type as AnsiString when using components as an Id. However I cannot figure out what to do in plain Id mappings.
I have tried using new NHibernate.Type.AnsiStringType(), but this complains about not having no constructors being defined for it.
Any ideas guys?
I had to explicitly cast the AnsiStringType to IIdentifierType and also set the length property.
Id(x => x.Id,
m =>
{
m.Generator(Generators.Assigned);
m.Type((IIdentifierType)TypeFactory.GetAnsiStringType(16));
m.Length(16);
});
Use NHibernate.Type.TypeFactory.GetAnsiStringType(someLength)
NHibernate.Type.TypeFactory.GetAnsiStringType(someLength) did not work in case of SetParameterList() so I changed it to NHibernateUtil.AnsiString. This changed the parameter to varchar(8000) which is still ok instead of nvarchar(4000) which was causing issues with change in execution plan choice.

Categories