Database structure with Entity Framework Core - Discrimination - asp.net-core

I have the following problem:
I'd like to be able sell a few kinds of products in my store.
I have created following infrastructure:
public class Product
{
public int Id {get; set;}
public string Name {get; set;}
...
public int? ParentId {get; set;}
public Product Parent {get; set;}
public ICollection<Product> Children {get; set;}
}
public class AudioFile : Product
{
public string SomeValue {get; set;}
}
public class DocummentFile : Product
{
public string SomeString {get; set;}
}
In fluent mapping I am using discriminator.
So, to Select the amount of documment files without a parent, I am doing something like this:
DbContext.DocummentFiles.Count(x=> !x.ParentId.HasValue)
It works with Audio files too.
I'd like to select sample dictionary of all children for some audio file with SomeValue:
DbContext.AudioFiles
.Where(x => x.ParentId == 222)
.Select(x => x.Children
.OfType<AudioFile>()
.ToDictionary(t => t.Name, t => t.SomeValue));
Unfortunately, it does not work. I have high CPU usage by the long time, but I have not any result.

Related

Entity Framework - Dropped a foreign key column successfully from table but getting an error while accessing the table

I am using a code first method to generate database. My models are as follows -
public class Employee
{
public int Id {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
[ForeignKey("ReferenceTbl1")]
public int Reference1Id {get; set;}
// Navigation property
public virtual Reference1 ReferenceTbl1 {get; set;}
}
public class Reference1
{
public int Id {get; set;}
public string Property1 {get; set;}
public string Property2 {get; set;}
}
The tables were created successfully using migration. The data was in both the tables.
Then after couple of months for some reason I had to change the schema. I had to create other table called Reference2. Drop the foreign key and column named "Reference1Id" from the table "Employee". And introduce another foreign key pointing to table "Reference2" in "Employee". So I made following changes in model
public class Employee
{
public int Id {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
[ForeignKey("ReferenceTbl1")]
public int Reference1Id {get; set;}
// New foreign key
[ForeignKey("ReferenceTbl2")]
public int Reference2Id {get; set;}
// Navigation property
public virtual Reference1 ReferenceTbl1 {get; set;}
// New navigation property
public virtual Reference2 ReferenceTbl2 {get; set;}
}
public class Reference2
{
public int Id {get; set;}
public string Property3 {get; set;}
public string Property4 {get; set;}
}
I successfully dropped the old foreign key and column from table "Employee" by creating new migration as follows
public override void Up()
{
DropForeignKey("dbo.Employee", "Reference1Id","dbo.Reference1");
DropIndex("dbo.Employee", new[] { "Reference1Id" });
DropColumn("dbo.Employee", "Reference1Id");
}
public override void Down()
{
AddColumn("dbo.Employee","Reference1Id",
e=>e.String(nullable:false,defaultValue: ""));
CreateIndex("dbo.Employee", "Reference1Id");
AddForeignKey("dbo.Employee", "Reference1Id",
"dbo.Reference1", "Id", cascadeDelete: true);
}
So after I ran the command "Update-database" in package manager console, the "Employee" table was updated exactly as I wanted with new foreign key column "Reference2Id" and no column with name "Reference1Id". I also altered the data appropriately.
But now when I try to access the table "Employee", it gives me this error "Invalid column name 'Reference1Id'".
The column "Reference1Id" is not present in the table "Employee" then why would this error occur?
I would really appreciate some help here.
Thanks

Trouble formulating inner joins using NHibernate Linq query

Using NHibernate 3.3.1.400, I'm having problems expressing what is a simple SQL statment using NHibernate's Linq provider.
My domain model looks like this:
public class Site
{
public virtual Guid Id {get; set;}
public virtual string Name {get; set;}
}
// a site has many filers
public class Filer
{
public virtual Guid Id {get set;}
public virtual Site Site {get; set;}
public virtual string Name {get; set;}
}
// a filer has many filings
public class Filing
{
public virtual Guid Id {get set;}
public virtual Filer Filer {get; set;}
public virtual DateTime FilingDate {get; set;}
}
//a filing has many items
public class Item
{
public virtual Guid Id {get set;}
public virtual Filing Filing {get; set;}
public virtual DateTime Date {get; set;}
public virtual decimal Amount {get; set;}
}
public class SearchName
{
public virtual Guid Id {get set;}
public virtual string Name {get; set;}
}
// there are potentially many NameLink objects tied to a single search name
public abstract class NameLink
{
public virtual Guid Id {get set;}
public virtual SearchName SearchName {get; set;}
}
public class NameLinkToFiler: NameLink
{
public virtual Filer Filer {get; set;}
}
public class NameLinkToItem: NameLink
{
public virtual Item Item {get; set;}
}
My query is supposed to return a list of matching Item elements:
var query = session.Query<Item>()
.Where(x => x.Filing.Filer.Site == mySite);
The joins connecting Site -> Filer -> Filing -> Item are working great through my mappings, but the problems start when I try to join the NameLinkToFiler or NameLinkToItem classes based on user input.
If the user wants to filter the Query results with a filer name, I want to join the results of the Item query with the results of this query:
var filerNameQuery = session.Query<NameLinkToFiler>()
.Where(q=>q.SearchName.Contains('some name'));
I want the results of the NameLinkToFiler.Filer property to join the Item.Filing.Filer property, so my list of returned items is reduced.
Note: The 'Contains' keyword above is a full-text index search I'm using as described here. It's working fine, and let's just assume the filerNameQuery is an IQueryable<NameLinkToFiler>.
It's pretty easy to do this in straight SQL:
select filer.Name, filing.FilingDate, filer.Name, item.Date, item.Amount
from Search_Name searchNameForFiler, Search_Name searchNameForItem, Name_Link_Filer nameLinkFiler,
Name_Link_Item nameLinkItem, Item item, Filing filing, Filer filer, Site s
where
contains(searchNameForFiler.Name, :filerName) and searchNameForFiler.Id = nameLinkFiler.SearchNameId and nameLinkFiler.FilerId = filer.Id and
contains(searchNameForItem.Name, :itemName) and searchNameForItem.Id = nameLinkItem.SearchNameId and nameLinkItem.ItemId = item.Id
and item.FilingId = filing.Id
and filing.FilerId = filer.Id
and filing.SiteId = :site
...but I don't want to lose the compile-time checks for this sort of query.
Thanks.
Apparently, the answer is to not use lambda syntax.
This works fine:
query = from t in parentItemQuery
join l in Session.Query<NameLinkToFiler>() on t.Filing.Filer.Id equals l.Filer.Id
join n in Session.Query<SearchName>() on l.SearchName.Id equals n.Id
where sn.Contains(request.FilerName)
select t;

Fluent NHibernate Mapping and Retrieve Hierarchy Table

I have a hierarchy category table like this
Id int,
Description varchar(100),
ParentId int,
Ordinal int,
IsActive bit
I want to fetch all of the Categories from parent to child, so when I called session.get<Category>(id), it already fetched all of their children. Here is my map and class:
class Category
{
public virtual int Id {get; set;}
public virtual string Description {get; set;}
public virtual int ParentId {get; set;}
public virtual int Ordinal {get; set;}
public virtual bool IsActive {get; set;}
}
class CategoryMap : ClassMap<Category>
{
public CategoryMap()
{
Table("TB_CATEGORY");
Id(f => f.Id).GeneratedBy.Native();
Map(f => f.Description);
Map(f => f.ParentId);
Map(f => f.Ordinal);
Map(f => f.IsActive);
}
}
I've searched so many articles, and am still confused when using their solutions because they don't tell me about the table structure and the mappings. Like this one from ayende blog, I think its a good solution, but I can't follow it well enough to apply this in my project.
Could somebody give me a step by step tutorial to achieve this? Are my mapping and class correct?
using the following classes
class Category
{
public virtual int Id {get; private set;}
public virtual string Description {get; set;}
public virtual Category Parent {get; set;}
public virtual bool IsActive {get; set;}
public virtual IList<Category> Children {get; private set;}
public override bool Euqals(object obj)
{
var other = obj as Category;
return other != null && (Id == 0) ? ReferenceEquals(other, this) : other.Id == Id;
}
public override int GetHashCode()
{
return Id;
}
}
class CategoryMap : ClassMap<Category>
{
public CategoryMap()
{
Table("TB_CATEGORY");
Id(f => f.Id).GeneratedBy.Native();
Map(f => f.Description);
References(f => f.Parent).Column("ParentId");
HasMany(f => f.Children)
.AsList(i => i.Column("Ordinal")) // let the list have the correct order of child items
.KeyColumn("ParentId")
.Inverse(); // let the reference maintain the association
Map(f => f.IsActive);
}
}
then you can query
var categoriesWithChildrenInitialised = session.QueryOver<Category>()
.Fetch(c => c.Children).Eager
.List()

Castle Active Record - Nested Data Column Prefix

I have a few classes structured similar to those shown below.
[ActiveRecord]
public class Request : ActiveRecordBase
{
[PrimaryKey]
public int Id {get; set;}
[Nested("SectionA")]
public SectionA A {get; set;}
[Nested("SectionB")]
public SectionB B {get; set;}
}
public class SectionA
{
[Property]
public string Description {get; set;}
[Property]
public string Remark {get; set;}
[HasMany(typeof(Attachment),
Table="Attachments", ColumnKey="RequestId",
Where="Section = 'SectionA'")]
public IList Attachments {get; set;}
}
public class SectionB
{
[Property]
public string Description {get; set;}
[HasMany(typeof(Attachment),
Table="Attachments", ColumnKey="RequestId",
Where="Section = 'SectionB'")]
public IList Attachments {get; set;}
}
[ActiveRecord]
public class Attachment
{
[PrimaryKey]
public int Id {get; set;}
[BelongsTo("RequestId")]
public Request Owner {get; set;}
[Property]
public string Section {get; set;}
[Property]
public string FilePath {get; set;}
}
Everything works fine, except that the columns for Attachment Class will have the prefix as well. And it happens quite randomly, as in some time it does have the prefix and sometime it doesn't.
Is there any way to prevent the Attachment from having the prefix, or is there a better way to structure my classes that prevent this issues.
Seems like way is prevent the nested prefix on Attachment class is to connect Request & Attachment directly. Still need to observe for a few iteration.
[ActiveRecord]
public class Request : ActiveRecordBase
{
[PrimaryKey]
public int Id {get; set;}
[HasMany(typeof(Attachment)]
public IList Attachments {get; set;}
[Nested("SectionA")]
public SectionA A {get; set;}
[Nested("SectionB")]
public SectionB B {get; set;}
}

NHibernate Criteria

public class A
{
public string aname {get; set;}
public string aId {get; set;}
public string bId {get; set;}
}
public class B
{
public string bId {get; set;}
public string bname {get; set;}
public string cId {get; set;}
}
public class C
{
public string cId {get; set;}
public string cfirstname {get; set;}
public string clastname {get; set;}
}
public class abcDTO
{
public string aname {get; set;}
public string bname {get; set;}
public string clastname {get; set;}
}
Evetually the query which I am looking is
SELECT a.aid, b.bname, c.clastname FROM A thisa
inner join B thisb on thisa.bid=thisb.bid
inner join C thisc on thisb.cid=thisc.cid and this_.POLICY_SEARCH_NBR like '%-996654%'
The criteria which I am trying is, Please let me know the best possible way to write a criteria so that I can get the abcdto object as result
var policyInsuranceBusiness = DetachedCriteria.For<A>()
.SetProjection(Projections.Property("a.aid"))
.Add(Restrictions.Like("a.aid", "1-SAP-3-996654", MatchMode.Anywhere))
.CreateCriteria("b.bid", "b", JoinType.InnerJoin)
.SetProjection(Projections.Property("b.bname")) // ERROR OUT - COULD NOT RESOLVE PROPERTY
.CreateCriteria("c.cid", "c", JoinType.InnerJoin)
.SetProjection(Projections.Property("c.clastname")); // ERROR - COULD NOT RESOLVE PROPERTY
IList<abcDTO> plo = policyInsuranceBusiness.GetExecutableCriteria(_session).SetResultTransformer(NHibernate.Transform.Transformers
.AliasToBean<abcDTO).List<abcDTO>();
You can't join objects in NHibernate without having a relationship between them defined in the classes and in the mappings.
So taking your example I would estimate the following class definitions:
public class A {
public virtual string Name {get; set;}
public virtual string PolicySearchNumber {get; set;}
public virtual int Id {get; set;}
public virtual B B {get; set;}
}
public class B {
public virtual int Id {get; set;}
public virtual string Name {get; set;}
public virtual C C {get; set;}
}
public class C {
public virtual int Id {get; set;}
public virtual string Firstname {get; set;}
public virtual string Lastname {get; set;}
}
public class abcDTO {
public string int aid {get; set;}
public string aname {get; set;}
public string bname {get; set;}
public string clastname {get; set;}
}
And your Criteria Query would be:
var results = session.CreateCriteria<A>()
.CreateCriteria("B", "b")
.CreateCriteria("b.C", "c")
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("Id"), "aid")
.Add(Projections.Property("Name"), "aname")
.Add(Projections.Property("b.Name"), "bname")
.Add(Projections.Property("c.Lastname"), "clastname")
)
.SetResultTransformer(new AliasToBeanResultTransformer(typeof(abcDTO)))
.List<abcDTO>();
You can optionally choose Inner or Left Joins depending on how you handle null references in the Criteria Query.