What wrong I am doing in IEnumerable(C#3.0) - linq

If I write
var v = (from r in stock.ReplacementLog
select new
{
AssetId = stock.AssetId,
Date = stock.ReferDate,
FactType = r.Key,
Value = r.Value
});
It is working fine...
But if I do
IEnumerable<StockAsset> v = (from r in stock.ReplacementLog
select new {
AssetId = stock.AssetId,
Date = stock.ReferDate,
FactType = r.Key,
Value = r.Value });
I am getting error:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?)
Then I did
IEnumerable<StockAsset> v =
(
from r in stock.ReplacementLog
select new
{
AssetId = stock.AssetId,
Date = stock.ReferDate,
FactType = r.Key,
Value = r.Value
}).ToList<StockAsset>();
With the following bunch of errors:
Error 1 Instance argument: cannot convert from 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.IEnumerable'
Error 2 'System.Collections.Generic.IEnumerable' does not contain a definition for 'ToList' and the best extension method overload 'System.Linq.Enumerable.ToList(System.Collections.Generic.IEnumerable)' has some invalid arguments
Then I tried with
IEnumerable<StockAsset> v1 =
(from r in stock.ReplacementLog
select new StockAsset
{
AssetId = stock.AssetId,
ReferDate= stock.ReferDate,
FactType = r.Key,
Value = r.Value
});
with the errors:
Error 1
'StockAsset' does not contain a definition for 'FactType'
**Error 2
'StockAsset' does not contain a definition for Value'**
The StockAsset Class is as under
public class StockAsset
{
public int AssetId { get; set; }
public DateTime ReferDate {get;set;}
public Dictionary<EnumFactorType, double> ReplacementLog { get; set; }
}
Need help.
Using C#3.0
Thanks

When you write
select new {
AssetId = stock.AssetId,
Date = stock.ReferDate,
FactType = r.Key,
Value = r.Value }
You actually generate an anonymous type. You can't cast this anonymous type to a declared type.
If you want to create an object of the class you should do
select new StockAsset
{
AssetId = ..., // Maybe stock.AssetId
ReferDate = ..., // Maybe stock.ReferDate
ReplacementLog = ... // Maybe new Dictionary<string, short> { {r.Key, r.Value} };
}

When you write
select new { property = value }
you're creating an instance of a new anonymous type, whereas it looks like you want to actually be creating StockAssets, so you want
select new StockAsset { property = value }

My best guess is that you're trying to create a new StockAsset for each entry in another StockAsset's ReplacementLog. This new StockAsset is going to have a single entry in its ReplacementLog. Is this correct? If so, you could create a new constructor on StockAsset:
public StockAsset(int assetId, DateTime referDate,
EnumFactorType factorType, double value)
{
AssetId = assetId;
ReferDate = referDate;
ReplacementLog = new Dictionary<EnumFactorType, double>();
ReplacementLog[factorType] = value;
}
And then call that constructor inside of your LINQ.
IEnumerable<StockAsset> v = (from r in stock.ReplacementLog
select new StockAsset(stock.AssetId, stock.ReferDate, r.Key, r.Value));

Related

decimal? with Left outer join gets null reference in LINQ

I am trying to do left outer join in LINQ for two vars but on selecting required coloumns, I get Object reference not set to an instance of an object error where I want Nullable decimal.
var FLS = (from ee in SumTillFYEnd
join es in SumTillFYStart on ee.Account equals es.Account into temp
from t in temp.DefaultIfEmpty()
select new
{
Account = ee.Account, // As of here it works
BeginDr = (t.DrStartCF == 0) ? (decimal?) null : t.DrStartCF // Here I get error Object reference not set to an instance of an object.
});
Some times SumTillFYEnd and some times SumTillFYStart becomes null. I want to join should work with default values, in case any one or both is null.
The problem is attempting to cast null to decimal?. You cannot ever directly cast null to another type, nullable or not. That will always cause a NullReferenceException. What you want instead is default. In other words, replace:
(decimal?)null
With
default(decimal?)
I solved this using a default class.
The reason I am seeing is that decimal can not be null so it either needs to set for a default value either 0 or decimal.MinValue
So, you require to have default class for SumTillFYStart like
var defaultSumTillFYStart = new SumTillFYStart { Account = string.Empty, DrStartCF =0};
With above in context, then in your piece of code replace
from t in temp.DefaultIfEmpty()
with this
from t in temp.DefaultIfEmpty(defaultSumTillFYStart)
I have a linqPad working written below but for different subset; I think it will help somebody:
void Main()
{
List<Debtor> debtors = new List<Debtor>();
List<SecurityHolding> holdings = new List<SecurityHolding>();
//Initialize Debtor
debtors.Add(new Debtor(){
AccountId = "J1",
OutstandingValue = 501.95M
});
debtors.Add(new Debtor(){
AccountId = "J2",
OutstandingValue = 75.68M
});
debtors.Add(new Debtor(){
AccountId = "J3",
OutstandingValue = 100.01M
});
//Initialize Security Holding
holdings.Add(new SecurityHolding(){
AccountId = "J2",
SecurityHoldingValue = 100M
});
holdings.Add(new SecurityHolding(){
AccountId = "J3",
SecurityHoldingValue = 200M
});
var defaultHolding = new SecurityHolding { AccountId= string.Empty, SecurityHoldingValue = 0};
var result = (from d in debtors
join p in holdings
on d.AccountId equals p.AccountId into temp
from t in temp.DefaultIfEmpty(defaultHolding)
select new
{
AccountId = d.AccountId,
OutstandingValue = d.OutstandingValue,
HoldingValue = (decimal?)t.SecurityHoldingValue
});
result.Dump();
}
// Define other methods and classes here
public class Debtor
{
public string AccountId {get;set;}
public decimal OutstandingValue {get;set;}
}
public class SecurityHolding
{
public string AccountId {get;set;}
public decimal SecurityHoldingValue {get;set;}
}
Here the output:

EF Core LINQ use scalar function

I use Entity Framework Core 2.1.
I have a scalar function in the database which adds specified number of days.
I created an extension method to execute it:
public static class AdventureWorks2012ContextExt
{
public static DateTime? ExecFn_AddDayPeriod(this AdventureWorks2012Context db, DateTime dateTime, int days, string periodName)
{
var sql = $"set #result = dbo.[fn_AddDayPeriod]('{dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}', {days}, '{periodName}')";
var output = new SqlParameter { ParameterName = #"result", DbType = DbType.DateTime, Size = 16, Direction = ParameterDirection.Output };
var result = db.Database.ExecuteSqlCommand(sql, output);
return output.Value as DateTime?;
}
}
I try to use a scalar function in the query (to simplify things I use AdventureWorks2012) as follows:
var persons =
(from p in db.Person
join pa in db.Address on p.BusinessEntityId equals pa.AddressId
where p.ModifiedDate > db.ExecFn_AddDayPeriod(pa.ModifiedDate, 100, "DayPeriod_day")
select p).ToList();
But get an System.InvalidOperationException: 'A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.'
How can I achieve this?
UPDATE:
I managed to do it with the help of Ivan's answer:
var persons =
(from p in db.Person
join bea in db.BusinessEntityAddress on p.BusinessEntityId equals bea.BusinessEntityId
join a in db.Address on bea.AddressId equals a.AddressId
where p.ModifiedDate > AdventureWorks2012ContextFunctions.AddDayPeriod(a.ModifiedDate, 100, "DayPeriod_day")
select p).ToList();
But now I need to update ModifiedDate for filtered persons. So I'm doing like this:
var persons =
(from p in db.Person
join bea in db.BusinessEntityAddress on p.BusinessEntityId equals bea.BusinessEntityId
join a in db.Address on bea.AddressId equals a.AddressId
let date = AdventureWorks2012ContextFunctions.AddDayPeriod(a.ModifiedDate, 100, "DayPeriod_day")
where p.ModifiedDate > date
select new { Person = p, NewDate = date }).ToList();
foreach (var p in persons)
p.Person.ModifiedDate = p.NewDate ?? DateTime.Now;
db.SaveChanges();
But got System.NotSupportedException: 'Specified method is not supported.'
How can I use scalar function in select statement?
I tried to split the query by two parts:
var filteredPersons = // ok
(from p in db.Person
join bea in db.BusinessEntityAddress on p.BusinessEntityId equals bea.BusinessEntityId
join a in db.Address on bea.AddressId equals a.AddressId
where p.ModifiedDate > AdventureWorks2012ContextFunctions.AddDayPeriod(a.ModifiedDate, 100, "DayPeriod_day")
select new { Person = p, a.ModifiedDate }).ToList();
var persons = // here an exception occurs
(from p in filteredPersons
select new { Person = p, NewDate = AdventureWorks2012ContextFunctions.AddDayPeriod(p.ModifiedDate, 100, "DayPeriod_day") }).ToList();
Instead of invoking the function client side (which is this particular case happens as part of the client evaluation of the query filter, while the query reading is still in progress), you can use EF Core Database scalar function mapping so it
can be used in LINQ queries and translated to SQL.
One way to do that is to create a public static method in the derived context class and mark it with DbFunction attribute:
public partial class AdventureWorks2012Context
{
[DbFunction("fn_AddDayPeriod")]
public static DateTime? AddDayPeriod(DateTime dateTime, int days, string periodName) => throw new NotSupportedException();
}
and use
where p.ModifiedDate > AdventureWorks2012Context.AddDayPeriod(pa.ModifiedDate, 100, "DayPeriod_day")
Another way is to create a public static method in another class
public static class AdventureWorks2012DbFunctions
{
[DbFunction("fn_AddDayPeriod")]
public static DateTime? AddDayPeriod(DateTime dateTime, int days, string periodName) => throw new NotSupportedException();
}
but then you'll need to register it with fluent API (which happens automatically for methods defined inside the context derived class):
modelBuilder
.HasDbFunction(() => AdventureWorks2012DbFunctions.AddDayPeriod(default(DateTime), default(int), default(string)));
The usage is the same:
where p.ModifiedDate > AdventureWorksDbFunctions.AddDayPeriod(pa.ModifiedDate, 100, "DayPeriod_day")

Conversion of a LINQ query fom method syntax to query syntax

Hi I am changing career to computer programming. I am still in college. I have to change the following LINQ query from method syntax to query syntax. What gets me is the 2 steps process of the method query. First it gets a teamId and then it returns a list based on the context and using the teamId. I am confused about how to translate this to query method. Most of the questions are about going from query syntax to method.
Can someone Help?
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = context
.TeamMembers
.Include("Team")
.FirstOrDefault(c => c.UserId == userId)
.Team.Id;
return context
.TeamTemplates.Include("Template")
.Where(c => c.TeamId == teamId)
.Select(c => c.Template)
.Where(c => c.StatusId == 1/*Active*/)
.Select(k => new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
}
}
The first one is pretty straight forward. I delayed the execution of the query until the end. Since you may get a null reference exception in your example accessing .FirstOrDefault().Team.Id;
var teamId = (from c in context.TeamMembers.Include("Team")
where c.UserId == userId
select c.Team.Id).FirstOrDefault();
This one you just need to use an into in order to continue your query statement
return (from c in context.TeamTemplates.Include("Template")
where c.TeamId == teamId
select c.Template into k
where k.StatusId == 1
select new TemplateView
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
}).ToList();
public IEnumerable<TemplateView> GetTemplates(Guid userId, int languageId)
{
using (DigigateEntities context = new Models.DigigateEntities())
{
var teamId = (from tm in context.TeamMembers.Include("Team")
where tm.UserId==userId
select tm.Id).FirstOrDefault();
IEnumerable<TemplateView> result = from k in (from tmp in context.TeamTemplates.Include("Template")
select tmp.Template)
where k.StatusId==1
select new
{
TemplateName = k.Name,
Id = k.Id,
IsCustom = k.Custom,
TypeId = k.TypeId,
TypeName = k.TemplateType.Description,
FileName = k.FileName,
TemplateImage = "test.png",
LanguageId = k.LanguageId,
LanguageName = k.Language.Name,
CreateDate = k.CreateDate
};
return result;
}

How to: linq query

I am trying to get a record from database using linq but it keep return no record
it is very basic sql statment
select * where productid ='12553'
however the following code does not return any result. Please advise. thx you
private static IEnumerable<ProductModel> GetAllProduct(string productId)
{
using (var dc = new TestEntities())
{
var result = (from a in dc.Products
where a.productid == productId
select new ProductModel
{
ProductId = a.productid,
Name = a.ProductName
});
return result.Distinct().ToList();
}
}
You don't need projection here:
using (var dc = new TestEntities())
{
var result = from a in dc.Products
where a.productid == productId
select a;
return result.Distinct().ToList();
}

EF single entity problem

I need to return a single instance of my viewmodel class from my repository in order to feed this into a strongly-typed view
In my repository, this works fine for a collection of viewmodel instances:
IEnumerable<PAWeb.Domain.Entities.Section> ISectionsRepository.GetSectionsByArea(int AreaId)
{
var _sections = from s in DataContext.Sections where s.AreaId == AreaId orderby s.Ordinal ascending select s;
return _sections.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
);
}
But when I attempt to obtain a single entity, like this:
public PAWeb.Domain.Entities.Section GetSection(int SectionId)
{
var _section = from s in DataContext.Sections where s.SectionId == SectionId select s;
return _section.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
);
}
I get
Error 1 Cannot implicitly convert type
'System.Linq.IQueryable<PAWeb.Domain.Entities.Section>' to
'PAWeb.Domain.Entities.Section'. An explicit conversion exists
(are you missing a cast?)"
This has got to be simple, but I'm new to c#, and I can't figure out the casting. I tried (PAWeb.Domain.Entities.Section) in various places, but no success. Can anyone help??
Your query is returning an IQueryable, which could have several items. For example, think of the difference between an Array or List of objects and a single object. It doesn't know how to convert the List to a single object, which one should it take? The first? The last?
You need to tell it specifically to only take one item.
e.g.
public PAWeb.Domain.Entities.Section GetSection(int SectionId)
{
var _section = from s in DataContext.Sections where s.SectionId == SectionId select s;
return _section.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
).FirstOrDefault();
}
This will either return the first item, or null if there are no items that match your query. In your case that won't happen unless the table is empty since you don't have a where clause.

Resources