So this is my entity:
public class Stock {
public Guid ID { get; set; }
public decimal Qty { get; set; }
.....
}
I have a lot of inheritance to this Stock:
public class StockA : Stock {
public string Spec { get; set; }
....
}
public class StockB : Stock {
public string Color { get; set; }
....
}
public class StockC : Stock {
public string Variant { get; set; }
....
}
public class StockD : Stock {
public string Type { get; set; }
....
}
.....
Let us say there are more than 10 inheritances. How can I get all columns from Stock and its inheritances?
For example I need these columns:
ID
Qty
Spec
Color
Variant
Type
....
I tried to define a combined entity:
public class AllStock {
public Guid ID { get; set; }
public decimal Qty { get; set; }
public string Spec { get; set; }
public string Color { get; set; }
public string Variant { get; set; }
public string Type { get; set; }
.....
}
I set it in my DBContext:
public DbSet<AllStock> AllStocks { get; set; }
But when I query it:
var x = await db.AllStocks.ToList();
It returns empty list. I suppose this AllStock entity is separated from the other entity.
How can I do it?
Try the following Select:
var result = await db.Stocks
.Select(x => new
{
x.ID,
x.Qty,
Spec = x is StockA ? ((StockA)x).Spec : null,
Color = x is StockB ? ((StockB)x).Color : null,
Variant = x is StockC ? ((StockC)x).Variant : null,
Type = x is StockD ? ((StockD)x).Type : null
})
.ToListAsync();
I am able to do this with FromSqlRaw.
First assign the DbSet:
public DbSet<StockVM> AllStocks { get; set; }
then set the model builder with HasNoKey:
mb.Entity<StockVM>().HasNoKey();
then this is the query:
return db.AllStocks.FromSqlRaw(#"
SELECT" +
GetSelect() +
#" FROM Stocks
INNER JOIN Colors ON Stocks.ColorId = Colors.ID
INNER JOIN Units ON Stocks.UnitId = Units.ID
INNER JOIN Items ON Stocks.ItemId = Items.ID
INNER JOIN ItemTypes ON Stocks.ItemTypeId = ItemTypes.ID
");
Also I have to create an entity with all of the properties:
public class StockVM{
public Guid ID { get; set; }
public decimal Qty { get; set; }
public string Spec { get; set; }
public string Color { get; set; }
public string Variant { get; set; }
public string Type { get; set; }
.....
}
IMPORTANT
Be careful with the migration, make sure you delete the AllStock from the Up(). Or it will try to create a new column.
Related
I am trying to add a property of a class from a query. I have two classes "Article & Source with manytomany relationship.
source:
public class Source
{
public Source()
{
this.Id = Guid.NewGuid();
}
public Guid Id { get; set; }
public int ApiId { get; set; }
public string? FullName { get; set; }
public string? Bio { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
article :
public class Article
{
public Article()
{
this.Id = Guid.NewGuid();
}
public Guid Id { get; set; }
public int ApiId { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public double Rating { get; set; }
public DateTime? AirDate { get; set; }
public virtual ICollection<Source> Cast { get; set; }
}
in my method, first I do a split then a query. I want to add the results of the query to the property Cast of my class Article
public void AddArticle(string name, string summary = null, string sources = " ", double rating = 5, DateTime? airDate = null)
{
using (var db = this._dataContextFactory.Create())
{
var sourcesDb = sources.Split(',').Select(a => db.Sources.Where<Source>(s => s.FullName == a).Include(s => s.Articles)).ToList();
db.Articles.Add(new Article()
{
Cast = (ICollection<Source>)sourcesDb.ToList(),
AirDate = airDate,
Rating = rating,
Summary = summary,
Title = name
}); ;
db.SaveChanges();
}
}
when I execute the code I have the following error :
exception {"Unable to cast object of type 'System.Collections.Generic.List1[Microsoft.EntityFrameworkCore.Query.IIncludableQueryable2[test1Project.Models.Source,System.Collections.Generic.ICollection1[test1Project.Models.Article]]]' to type 'System.Collections.Generic.ICollection1[test1Project.Models.Source]'."} System.InvalidCastException
Thank you for your help
Thank you , I edited my method to
var arrayOfString = sources.Split(','); var sourcesDb =db.Sources.Where(s => arrayOfString.Contains(s.FullName)).Include(s => s.Articles).ToList();
and it works . Thanks again –
I am trying to populate the AllTerms object that will contain LegalFundClassCommercialViewModel and LegalFundClassSideLetterViewModel objects.
Basically the LEGAL_FUND_CLASS table has parent and child records and are related by column LegalParentClassId. One parent has one child. So I need to loop through legalfundClasses object and populate
IEnumerable<LegalFundClassWrapper> AllTerms . The LegalFundClassDetailsViewModel represents the records in the LEGAL_FUND_CLASS table. So legalfundClasses variable contains records from this legal_fund_class table. There are several records. Some records wont have child record. I need to populate in a way where the parent record gets added to LegalFundClassCommercialViewModel and its child record gets added to
LegalFundClassSideLetterViewModel. The wrapper would contain a collection of Parent and child records where some child records wont exist and hence the LegalFundClassSideLetterViewModel property would be null.
Can somebody give me an idea on how to go about it ?
C#
public class LegalFundClassViewModel
{
public IEnumerable<LegalFundClassWrapper> AllTerms;
public class LegalFundClassWrapper
{
public LegalFundClassDetailsViewModel LegalFundClassCommercialViewModel { get; set; }
public LegalFundClassDetailsViewModel LegalFundClassSideLetterViewModel { get; set; }
}
}
public class LegalFundClassDetailsViewModel
{
public string Description { get; set; }
public string AuditSummary { get; set; }
public string FeesReviewSummary { get; set; }
public string TermsReviewSummary { get; set; }
public int Id { get; set; }
public int FundId { get; set; }
public int FundClassType { get; set; }
public int? CurrencyId { get; set; }
public string PrimaryCurrencyName { get; set; }
public string OtherCurrencyName { get; set; }
public int? ManagerStrategyId { get; set; }
public string ManagerStrategyName { get; set; }
public int? SubVotingId { get; set; }
public string SubVotingName { get; set; }
public int? SubHotIssueId { get; set; }
public string SubHotIssueName { get; set; }
public int? RedsFrqncyId { get; set; }
public string RedsFrqncyName { get; set; }
public int? RedsNoticeDays { get; set; }
public int? NoticeTypeOfDaysId { get; set; }
public string NoticeTypeOfDaysName { get; set; }
public int? LegalParentClassId { get; set; }
}
var managerStrategyFundIds = GetService<MANAGERSTRATEGY>().WhereWithIncludes<MANAGERSTRATEGY>(x => x.ID == managerStratedyId, x => x.FUNDs).SelectMany(x => x.FUNDs).Select(x => x.ID).ToList();
var legalfundClasses = GetService<LEGAL_FUND_CLASS>().Where(x => managerStrategyFundIds.Contains(x.FUND_ID));
What I was trying creates a list of all the records in one. How do I loop through and populate the AllTerms
var allFunds = legalfundClasses.Select(fc => new LegalFundClassDetailsViewModel
{
Description = fc.DESCRIPTION,
Id = fc.ID,
FundId = fc.FUND_ID,
FundClassType = fc.CLASS_TYPE,
AuditSummary = getAuditSummary(managerStratedyId, fc.ID),
FeesReviewSummary = getFeesReviewSummary(fc),
TermsReviewSummary = getTermsReviewSummary(fc),
CurrencyId = fc.CURRENCY_ID,
});
public class LegalFundClassViewModel
{
public IEnumerable<LegalFundClassWrapper> AllTerms;
public class LegalFundClassWrapper
{
public LegalFundClassDetailsViewModel
LegalFundClassCommercialViewModel { get; set; }
public LegalFundClassDetailsViewModel
LegalFundClassSideLetterViewModel { get; set; }
}
As you can see in the image below, there are two records. The record that has value in legal_parent_class id field is the child to the record on top of it. If you notice the id of the top record matches the bottom record's legal_parent_class_id.
What is the best way to identify the child and store records in respective properties accordingly
You need left outer join. In your case
var allFunds = new[]
{
new LegalFundClassDetailsViewModel
{
Id = 101,
Description = "Parent with child"
},
new LegalFundClassDetailsViewModel
{
Id = 102,
Description = "Parent without child"
},
new LegalFundClassDetailsViewModel
{
Id = 103,
Description = "I'm child",
LegalParentClassId = 101
}
};
var allTerms = (from fund in allFunds
where fund.LegalParentClassId == null //only parents
join child in allFunds on fund.Id equals child.LegalParentClassId into gj
from child2 in gj.DefaultIfEmpty()
select new LegalFundClassViewModel.LegalFundClassWrapper { LegalFundClassCommercialViewModel = fund, LegalFundClassSideLetterViewModel = child2 })
.ToArray();
I am relatively new to .net. I have a situation where I have a class
public class Product
{
public string sku { get; set; }
public string ean { get; set; }
public string price { get; set; }
public string description { get; set; }
public string long_description { get; set; }
public string img_url { get; set; }
public Size size { get; set; }
public Style style { get; set; }
public Brand brand { get; set; }
public Color color { get; set; }
public Category category { get; set; }
public List<Attributes> attributes { get; set; }
}
public class Attributes
{
public List<Attribute> attribute { get; set; }
}
public class Attribute
{
public string name { get; set; }
public string value { get; set; }
}
now my question is I want to add values to List.But facing some problem in adding values to attribute.
I have tried the following,
List<Product> products = new List<Product>();
products = (from inventory in inventoryDetails.AsEnumerable()
select new Product
{
ean = !string.IsNullOrEmpty(inventory.ean) ? inventory.ean : null,
sku = !string.IsNullOrEmpty(inventory.sku) ? inventory.sku : null,
}).ToList();
How to add attribute values? Can anyone please help?
You have multiple ways to write this
without lambda expression
List<Product> products = (from inventory in inventoryDetails.AsEnumerable()
select new Product
{
ean = !string.IsNullOrEmpty(inventory.ean) ? inventory.ean : null,
sku = !string.IsNullOrEmpty(inventory.sku) ? inventory.sku : null,
attributes = inventory.attributes.Select(x => new Attributes
{
//Set properties
}).ToList()
}).ToList();
With Lambda Expression
List<Product> products = inventoryDetails.Select(inventory => new Product
{
ean = !string.IsNullOrEmpty(inventory.ean) ? inventory.ean : null,
sku = !string.IsNullOrEmpty(inventory.sku) ? inventory.sku : null,
attributes = inventory.attributes
// if you want to set properties uncomment below lines and comment above line
//attributes = inventory.attributes.Select(y => new Attributes
//{
////Set properties
//}).ToList()
}).ToList();
You didn't share about inventoryDetails but you could apply select for also attributes;
products = (from inventory in inventoryDetails.AsEnumerable()
select new Product
{
ean = !string.IsNullOrEmpty(inventory.ean) ? inventory.ean : null,
sku = !string.IsNullOrEmpty(inventory.sku) ? inventory.sku : null,
attributes = inventory.attributes.Select(x => new Attributes
{
//Set properties
})
}).ToList();
When a model class cantains a List or collection fields we must intiate them at class constructor like this
public class Product
{
public Product()
{
this.attributes = new List<Attributes>();
}
public string sku { get; set; }
public string ean { get; set; }
public string price { get; set; }
public string description { get; set; }
public string long_description { get; set; }
public string img_url { get; set; }
public Size size { get; set; }
public Style style { get; set; }
public Brand brand { get; set; }
public Color color { get; set; }
public Category category { get; set; }
public List<Attributes> attributes { get; set; }
}
If any case Attribues model is mapped to database then use Icollection instead of List
public Product()
{
this.attributes = new ICollection<Attributes>();
}
I have this SQL query which works:
select sum(dbos.Points) as Points, dboseasons.Year
from dbo.StatLines dbos
inner join dbo.Games dbog on dbog.GameId = dbos.GameId
inner join dbo.Seasons dboseasons on dbog.Season_SeasonId = dboseasons.SeasonId
where dbos.PlayerId = 3
group by dboseasons.Year
It returns Points, Year (56, 2016)
I'm trying to convert this to a Linq query to use with EF.
I have
var query =
from dbostats in _db.StatLines
join dbogames in _db.Games on dbostats.GameId equals dbogames.GameId
join dboseasons in _db.Seasons on dbogames.Season.SeasonId equals dboseasons.SeasonId
where dbostats.PlayerId == player.PlayerId
group dbostats.Points by dboseasons.Year into g
select new
{
Year = g.Key,
Points = g.Sum()
};
playerAndStatLines.StatLinesBySeason =
query
.ToList()
.Select( r => new StatsBySeason
{
Season = r.Year,
Points = r.Points
});
Which returns an empty result set.
When I view the SQL its generating, it's this:
SELECT
[GroupBy1].[K1] AS [Year],
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
[Extent3].[Year] AS [K1],
SUM([Extent1].[Points]) AS [A1]
FROM [dbo].[StatLines] AS [Extent1]
INNER JOIN [dbo].[Games] AS [Extent2] ON [Extent1].[GameId] = [Extent2].[GameId]
INNER JOIN [dbo].[Seasons] AS [Extent3] ON [Extent2].[Season_SeasonId] = [Extent3].[SeasonId]
WHERE ([Extent1].[Discriminator] IN (N'StatsBySeason',N'StatLines')) AND ([Extent1].[PlayerId] = 3)
GROUP BY [Extent3].[Year]
) AS [GroupBy1]
Which, as expected, returns an empty result set when executed against my DB.
The problem seems to be this bit:
([Extent1].[Discriminator] IN (N'StatsBySeason',N'StatLines')) AND
If I take this out and run the generated query then I get back my 2016, 56 result.
What is this Extent1.Discriminator, why is it generating it from my Linq query?
My Model classes:
public class PlayerAndStatLines
{
public PlayerWithTeam PlayerWithTeam { get; set; }
public IEnumerable<StatsBySeason> StatLinesBySeason { get; set; }
}
public class Season
{
public int SeasonId { get; set; }
public int Year { get; set; }
}
public class Game
{
public int GameId { get; set; }
public int HomeTeamId { get; set; }
public int AwayTeamId { get; set; }
public int HomeScore { get; set; }
public int AwayScore { get; set; }
public DateTime DatePlayed { get; set; }
public GameType GameType { get; set; }
public int? PlayoffGameNumber { get; set; }
public Season Season { get; set; }
}
public class StatLines
{
public int StatLinesId { get; set; }
public int GameId { get; set; }
public int PlayerId { get; set; }
public int TeamId { get; set; }
public int Points { get; set; }
public int DefensiveRebounds { get; set; }
public int OffensiveRebounds { get; set; }
public int Assists { get; set; }
public int Turnovers { get; set; }
public int Minutes { get; set; }
public int Steals { get; set; }
public int Blocks { get; set; }
public int Fouls { get; set; }
public int ThreePointFieldGoalsAttempted { get; set; }
public int ThreePointFieldGoalsMade { get; set; }
public int TwoPointFieldGoalsAttempted { get; set; }
public int TwoPointFieldGoalsMade { get; set; }
public int FreeThrowsMade { get; set; }
public int FreeThrowsAttempted { get; set; }
public bool Started { get; set; }
}
public class StatsBySeason : StatLines
{
public int Season { get; set; }
public string SeasonYears => Season + " / " + (Season + 1);
}
If I run the following SQL:
select Discriminator from dbo.StatLines
I get 2 rows back, both empty.
Thank you.
Be very careful (avoid if possible) of inheriting an entity class inside the same assembly. EF discovers the derived class and decides that you want to use TPH inheritance strategy and silently (in case you are using automatic migrations) creates and uses Discriminator column, which of course is empty for the existing data and breaks your queries.
I see two options:
Replace inheritance with containment:
public class StatsBySeason
{
public int Season { get; set; }
public StatLines StatLines { get; set; }
public string SeasonYears => Season + " / " + (Season + 1);
}
Let EF ignore the StatsBySeason class using Fluent configuration:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<StatsBySeason>();
// ...
}
or data annotation:
[NotMapped]
public class StatsBySeason : StatLines
{
// ...
}
Below is the Entity class
public partial class TestPlanViewModel
{
public TestPlanViewModel()
{
this.TestPlanTestPoints = new List<TestPlanTestPoint>();
}
public int TestPlanId { get; set; }
public string TestPlanName { get; set; }
public virtual IList<TestPlanTestPoint> TestPlanTestPoints { get; set; }
}
public class TestPlanTestPoint
{
public int OrganizationId { get; set; }
public int TestPlanId { get; set; }
public string TestPlanName { get; set; }
public int TestPlanVersion { get; set; }
public int TestPointId { get; set; }
public string TestPointName { get; set; }
}
I need to write a query where I need to get the collections from the dbContext like,
var query = (from tpm in TestPlanMaster
join tptp in TestPlanTestPoint on tpm.TestPlanId equals tptp.TestPlanId
join tmm in TestMethodMaster on tptp.TestMethodId equals tmm.TestMethodId
join tpma in TestPointMaster on tptp.TestPointId equals tpma.TestPointId
select new
{
//Plan Details
tpm.TestPlanId,
tpm.TestPlanName,
}).ToList().Select(x => new Entities.CustomEntities.TestPlanViewModel ====> Custom Entity
{
TestPlanId = x.TestPlanId,
TestPlanName = x.TestPlanName,
TestPlanTestPoints = ?????? ==> how to fill this collection
});
As shown above the TestPlanTestPoints is the IList collection object. I need to populate the data with the values from TestPlanTestPoint table.
Any suggestions?
Model
TestPlan
public partial class TestPlanMaster
{
[DataMember]
public int TestPlanId { get; set; }
[DataMember]
public short TestPlanVersion { get; set; }
[DataMember]
public int OrganizationId { get; set; }
[DataMember]
public short TestPlanTypeId { get; set; }
[DataMember]
public string TestPlanName { get; set; }
}
TestPlanTestPointMapping Model
public partial class TestPlanTestPointMapping
{
[DataMember]
public int OrganizationId { get; set; }
[DataMember]
public int TestPlanId { get; set; }
[DataMember]
public short TestPlanVersion { get; set; }
[DataMember]
public int TestPointId { get; set; }
}
You are thinking too much sql, think more linq. You want to select "tpm" items, so just write a select of those and select the new TestPlanViewModel and fill its properties and navigational properties.
I'm assuming you have a TestPlanTestPoints navigational property in your TestPlanMaster.
var q = (from tpm in TestPlanMaster
select new TestPlanViewModel
{
TestPlanId = tpm.TestPlanId,
TestPlanName = tpm.TestPlanName,
TestPlanPoints = TestPlanTestPoint.Where(pr => tpm.TestPlanId == pr.TestPlanId).Select(tptp => new TestPlanTestPoint()
{
// Fill properties here
}
}).ToList();