I am new in LINQ and I have a problem.
I have two tables in two different dbContext(userContext and mailContext). I want to select a part of data from UserAccount table, after I add this data to UserMail table. UserAccount table have lots of columns and UserMail tables have 4 columns (CreatedDate, UserAccountId, UserType, ItemCount)
The selection code:
var selectedUsers = _userContext.UserAccount
.Where(x=>x.Created == new DateTime(2021, 02, 17))
.Select(x => new UserMail()
{
CreatedDate = x.Created,
UserAccountId = x.AccountId,
UserType = x.UserType,
ItemCount = (int?)x.ItemCount,
}).ToList();
The query return null, The count of selectedUsers=0. I check from SQL, some data exits, am I miss a point in the query?
Actually, I need the sum of ItemCount grouped by AccountId and CreatedDate but first of all, I want to get the result of this query.
It means you can't satisfy the where condition since highly likely hours/minutes/seconds parts are not equal each other. What about the following?
var selectedUsers = _userContext.UserAccount
.Where(x=>x.Created.Date == new DateTime(2021, 02, 17).Date)
// new DateTime(2021, 02, 17) could be used simply but the default
// behavior may be changed in future.
.Select(x => new UserMail()
{
CreatedDate = x.Created,
UserAccountId = x.AccountId,
UserType = x.UserType,
ItemCount = (int?)x.ItemCount,
}).ToList();
Related
how to get just special 2 attributes from a table to other table( and placement in related textbox) by LINQ??
public string srcht(ACTIVITIES sn)
{
db db = new db();
var q = (from i in db.costumers.Where(i => i.id== sn.id)select i.name).ToList();
return q.Single();
}
public string srcht(ACTIVITIES sn)
{
db db = new db();
var q = (from i in db.costumers.Where(i => i.id== sn.id)select i.family).ToList();
return q.Single();
}
i did linq twice to fill 2 textboxes by name and family in other table. can i do it by one LINQ?
So you have an Activity in sn, and you want the Name and the Family of all Customers that have an Id equal to sn.Id.
var result = db.Customers.Where(customer => customer.Id == sn.Id)
.Select(customer => new
{
Name = customer.Name,
Family = customer.Family,
});
In words: in the database, from the table of Customers, keep only those Customers that have a value for property Id that equals the value of sn.Id. From the remaining Customers select the values of Name and Family.
If you expect that there will only be at utmost one such customer (so if Id is the primary key), just add:
.FirstOrDefault();
If you think there will be several of these customers, add:
.ToList();
The result will be an object, or a list of objects of some anonymous type with two properties: Name and Family.
If you want to mix the Name and the Family in one sequence of strings, which I doubt, consider to put the Name and the Family in an array. Result is sequence of arrays of strings. To make it one array of Strings, use SelectMany:
var result = db.Customers
.Where(customer => customer.Id == sn.Id)
.Select(customer => new string[]
{
customer.Name,
customer.Family,
})
.SelectMany(customer => customer);
I've got the following container class:
public class AssetAndItsDepositsContainer
{
public jp_asset Asset { get; set; }
public jp_deposit Deposit { get; set; }
}
Is there a way to take the following LINQ query:
from a in serviceContext.jp_assetSet
join d in serviceContext.jp_depositsSet on a.Id equals d.jp_assetid.Id
where a.statecode == jp_assetState.Active &&
a.jp_isonhold = true
select new AssetAndItsDepositsContainer()
{
Asset = a,
Deposit = d
})
.ToList();
And "translate" it by using QueryExpression?
This is what I came up with so far, but I don't know how to mimic the select new expression:
QueryExpression query = new QueryExpression(jp_asset.EntityLogicalName);
query.ColumnSet = new ColumnSet(true);
query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)jp_assetState.Active);
query.Criteria.AddCondition("jp_isonhold", ConditionOperator.Equal, true);
LinkEntity link = query.AddLink(jp_deposit.EntityLogicalName, "Id", "jp_assetid", JoinOperator.Inner);
// Now what?
var res = service.RetrieveMultiple(query).Entities; // gets only jp_assets
You can't access an entire LinkEntity, you can only access its attributes as AliasedValue properties on the main Entity itself.
I would simply retrieve the Id of the second record you're looking for as part of an EntityReference and then execute a Retrieve.
You can actually construct valid Entity objects from linked entities. The only requirement is that the primary key of the linked entity must be available in the result set.
So, your code snippet could be extended like this:
var query = new QueryExpression(jp_asset.EntityLogicalName);
query.ColumnSet.AllColumns = true;
query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)jp_assetState.Active);
query.Criteria.AddCondition("jp_isonhold", ConditionOperator.Equal, true);
LinkEntity link = query.AddLink(jp_deposit.EntityLogicalName, "Id", "jp_assetid", JoinOperator.Inner);
link.EntityAlias = "d";
link.Columns.AddColumns("jp_depositid", "jp_name");
IEnumerable<Entity> deposits = Service.RetrieveMultiple(query).Entities
.Select(e => new Entity("jp_deposit")
{
Id = (Guid)e.GetAttributeValue<AliasedValue>("d.jp_depositid").Value,
["jp_name"] = e.GetAttributeValue<AliasedValue>("d.jp_name")?.Value
});
Note
The example above will only work reliable for inner joins. In the result set the primary key (ID) for the linked entity will always be available. Therefore it is safe to get its value using the .Value syntax. All other attribute values can be retrieved using ?.Value.
For left joins you would need to filter the result set first before performing the Select.
I am trying to fill a viewmodel(List) from Datatable.
Customer and WorkingTime
WorkingTime is a child List of Customer. There are several entries for a Customer.
Using Adapter.Fill Meathod
DataTable dtCust=GetCustomersInTable(Uid);
DataTable dtWorking=GetAllCustWorkTimeInTable(Uid);
var Customers = (from C in dtCust.AsEnumerable()
select new CustomerViewModel
{
CustomerId = (long)C["CustomerId"],
Address1 = DBNull.Value == C["Name"] ? "" : Convert.ToString(C["Name"]),
Address2 = DBNull.Value == C["Address"] ? "" : Convert.ToString(C["Address"]),
City = DBNull.Value == C["City"] ? "" : Convert.ToString(C["City"]),
WorkingTime = GetCustWorkingTime(dtWorking, Convert.ToInt64(C["CustomerId"])),
}}).ToList();
private List<CustomerWorkingTime> GetCustWorkingTime(DataTable dtWorking, long CustomerId)
{
var CustomerWorkingTimes = (from C in dtWorking.AsEnumerable()
where Convert.ToInt64(C["CustomerId"]) == CustomerId
select new CustomerWorkingTime
{
AfterNoonFrom = Convert.ToDateTime(C["AfterNoonFrom"]),
AfterNoonUntil = Convert.ToDateTime(C["AfterNoonUntil"])
}).ToList();
return result;
}
I need to take whole data. It used not for displaying in UI.
This meathod is taking too much time to fill data. especially CustomerWorkingtime Filling.
Please suggest a better method to fill data.
Pagination is not possible here.
Existing setup is in EntityFramework and performance is poor.
Yu can try playing around with the TPL Parallel.ForEach, I think in your case this might give you a boost.
for example:
var Customers = Parallel.ForEach(dtCust.AsEnumerable(), c =>
select new CustomerViewModel
{
CustomerId = (long)C["CustomerId"],
Address1 = DBNull.Value == C["Name"] ? "" : Convert.ToString(C["Name"]),
Address2 = DBNull.Value == C["Address"] ? "" : Convert.ToString(C["Address"]),
City = DBNull.Value == C["City"] ? "" : Convert.ToString(C["City"]),
WorkingTime = GetCustWorkingTime(dtWorking, Convert.ToInt64(C["CustomerId"])),
}}).ToList();
Or in your "GetCustWorkingTime":
var result= dtWorking
.AsEnumerable()
.AsParallel()
.Where(c => Convert.ToInt64(C["CustomerId"]) == CustomerId)
.Select(c= > new CustomerWorkingTime
{
AfterNoonFrom = Convert.ToDateTime(C["AfterNoonFrom"]),
AfterNoonUntil = Convert.ToDateTime(C["AfterNoonUntil"])
}).ToList();
you should try them separately, and together, to see which one gives you the best performance (depends on the size of the tables).
Note: using both together might cause problems since in "GetCustWorkingTime" you'll end up iterating over the same table by multiple tasks in the same time.
I am having some trouble with a linq query I am trying to write.
I am trying to use the repository pattern without to much luck. Basically I have a list of transactions and a 2nd list which contains the description field that maps against a field in my case StoreItemID
public static IList<TransactionViewModel> All()
{
var result = (IList<TransactionViewModel>)HttpContext.Current.Session["Transactions"];
if (result == null)
{
var rewardTypes = BusinessItemRepository.GetItemTypes(StoreID);
HttpContext.Current.Session["Transactions"] =
result =
(from item in new MyEntities().TransactionEntries
select new TransactionViewModel()
{
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
}).ToList();
}
return result;
}
public static List<BusinessItemViewModel>GetItemTypes(int storeID)
{
var result = (List<BusinessItemViewModel>)HttpContext.Current.Session["ItemTypes"];
if (result == null)
{
HttpContext.Current.Session["ItemTypes"] = result =
(from items in new MyEntities().StoreItems
where items.IsDeleted == false && items.StoreID == storeID
select new BusinessItemViewModel()
{
ItemDescription = items.Description,
StoreID = items.StoreID,
StoreItemID = items.StoreItemID
}).ToList();
}
return result;
However I get this error
Unable to create a constant value of type 'MyMVC.ViewModels.BusinessItemViewModel'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
I know its this line of code as if I comment it out it works ok
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID).ItemDescription,
How can I map ItemDescription against my list of itemTypes?
Any help would be great :)
This line has a problem:
ItemDescription = itemTypes.FirstOrDefault(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription,
Since you are using FirstOrDefault you will get null as default value for a reference type if there is no item that satifies the condition, then you'd get an exception when trying to access ItemDescription - either use First() if there always will be at least one match or check and define a default property value for ItemDescription to use if there is none:
ItemDescription = itemTypes.Any(r=>r.StoreItemID==item.StoreItemID)
? itemTypes.First(r=>r.StoreItemID==item.StoreItemID)
.ItemDescription
: "My Default",
If itemTypes is IEnumerable then it can't be used in your query (which is what the error message is telling you), because the query provider doesn't know what to do with it. So assuming the that itemTypes is based on a table in the same db as TransactionEntities, then you can use a join to achieve the same goal:
using (var entities = new MyEntities())
{
HttpContext.Current.Session["Transactions"] = result =
(from item in new entities.TransactionEntries
join itemType in entities.ItemTypes on item.StoreItemID equals itemType.StoreItemID
select new TransactionViewModel()
{
ItemDescription = itemType.ItemDescription,
TransactionDate = item.PurchaseDate.Value,
TransactionAmount = item.TransactionAmount.Value,
CustomerName = rewards.CardID//TODO: Get customer name
}).ToList();
}
I don't know the structure of your database, but hopefully you get the idea.
I had this error due a nullable integer in my LINQ query.
Adding a check within my query it solved my problem.
query with problem:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.Equals(y.OBJ_ID));
query with problem solved:
var x = entities.MyObjects.FirstOrDefault(s => s.Obj_Id.HasValue && s.Obj_Id.Value.Equals(y.OBJ_ID));
Lets say that I need to execute this query with EF in business layer
var list = context.Invoices.Select(x => new
{
InvoiceNumber = x.InvoiceNUmber,
InvoiceDate = x.InvoiceDate,
CustomerName = x.Customer.CustomerName,
TotalValue = x.InvoiceData.Sum(y => y.Quantity * y.Price),
Id = x.Id
}).ToList();
What can I do for this list to be easily sortable, searchable or filterable in UI layer?
Thanks,
Goran
The way to do it is to return a object that is not anonymous. That is, create a class to hold this data. It should either have an implicit zero-argument constructor (because you have no constructors), or an explicit zero-argument one (because you have defined other constructors). Then you can say:
List<MyObject> list = context.Invoices.Select(x => new MyObject()
{
InvoiceNumber = x.InvoiceNUmber,
InvoiceDate = x.InvoiceDate,
CustomerName = x.Customer.CustomerName,
TotalValue = x.InvoiceData.Sum(y => y.Quantity * y.Price),
Id = x.Id
}).ToList();
Now you can return the strongly-typed list of objects out of your business layer, and your UI layer can use LINQ (or whatever) to do sorting/filtering/paging.