How to make a custom order with Dictionary in C#? - c#

I am trying to sort all the items in a list according to their status. I tried to do it in the following way with the Dictionary but it gives me an error. Could you help me to do it correctly?
The order according to their status should be as follows: Activated, Paused, Expired and Drained.
var table = _plapsaContext.Coupons;
var query = _plapsaContext.Coupons.AsQueryable();
query.Select(e => new CouponDto{
Id = e.Id,
StartingDate = e.StartingDate,
EndingDate = e.EndingDate,
Amount = e.Amount,
TotalCoupons = e.TotalCoupons,
MinimumAmount = e.MinimumAmount,
RestCoupons = e.RestCoupons,
ContractId = e.ContractId,
Status = (e.EndingDate.Date < DateTime.Now.Date && e.Status != CouponStatus.Paused && e.Status != CouponStatus.Drained) ? CouponStatus.Expired : e.Status,
ContractCode = e.ContractId.HasValue ? e.Contract.Code.ToString() : null,
OwnerAssociationCode = e.OwnerAssociactionCode,
BuildingManagerName = e.ContractId.HasValue ? e.Contract.BuildingManagerName : null,
ExcludeFunctionalUnits = e.ExcludeFunctionalUnits
});
Dictionary<CouponStatus, int> orderCoupons = new Dictionary<CouponStatus, int>
{
{ CouponStatus.Activated, 0 },
{ CouponStatus.Paused, 1 },
{ CouponStatus.Expired, 2 },
{ CouponStatus.Drained, 3 },
};
Array.Sort(query.ToArray(), (p, q) => orderCoupons[p.Status].CompareTo(orderCoupons[q.Status]));
Console.WriteLine(query);
return (IQueryable<CouponDto>)query;
I hope you can help me! Thank you very much!

This query should sort in desired way. I don't think that you need sorting dictionary here. The following query will sort data on the server side.
var query = _plapsaContext.Coupons.AsQueryable();
var dtoQuery = query
.Select(e => new CouponDto
{
Id = e.Id,
StartingDate = e.StartingDate,
EndingDate = e.EndingDate,
Amount = e.Amount,
TotalCoupons = e.TotalCoupons,
MinimumAmount = e.MinimumAmount,
RestCoupons = e.RestCoupons,
ContractId = e.ContractId,
Status = (e.EndingDate.Date < DateTime.Now.Date && e.Status != CouponStatus.Paused && e.Status != CouponStatus.Drained) ? CouponStatus.Expired : e.Status,
ContractCode = e.ContractId.HasValue ? e.Contract.Code.ToString() : null,
OwnerAssociationCode = e.OwnerAssociactionCode,
BuildingManagerName = e.ContractId.HasValue ? e.Contract.BuildingManagerName : null,
ExcludeFunctionalUnits = e.ExcludeFunctionalUnits
});
dtoQuery = dtoQuery
.OrderBy(e => e.Status == CouponStatus.Activated ? 0
: e.Status == CouponStatus.Paused ? 1
: e.Status == CouponStatus.Expired ? 2
: e.Status == CouponStatus.Drained : 3
);
return dtoQuery;

Related

Unable to create a constant value of type Only primitive types or enumeration types are supported in this context.:

I have the following code..
var GetStock = db.tabStocks.Where(x => x.SourceDocRef == InvoiceNumber.Text);
List<tabStock> tbs = new List<tabStock>();
foreach (var Stk in GetStock)
{
switch (GetStock.Any(y => y.ProductSKU == Stk.ProductSKU && y.Id != Stk.Id))
{
case true:
if (!(tbs.AsEnumerable().Any(x => x.Id == Stk.Id))) {
tbs.Add(Stk);
}//tbs.AddRange(GetStock2.Where(g => g.ProductSKU == Stk.ProductSKU && g.Id != Stk.Id));
var GetOthers = GetStock.Where(x => x.Id != Stk.Id && x.ProductSKU == Stk.ProductSKU );
foreach (var Gt in GetOthers) {
if (!(tbs.AsEnumerable().Any(x => x.Id == Gt.Id))) {
tbs.Add(Gt);
}
} break;
}
}
//Group and Remove tbs
Literal1.Text += tbs.AsEnumerable().Count();
try
{
var GroupIt = tbs.GroupBy(x => x.ProductSKU ).AsEnumerable()
.Select(g => new tabStock
{
ProductName = g.FirstOrDefault().ProductName,
ProductSKU = g.FirstOrDefault().ProductSKU,
Qty = g.Sum(n => n.Qty).Value,
OutQty = g.Sum(n => n.Qty).Value,
Bal = (db.tabStocks.Any(x => x.ProductSKU == g.FirstOrDefault().ProductSKU && x.SourceDocRef != g.FirstOrDefault().SourceDocRef && x.Id < g.OrderBy(t => t.Id).FirstOrDefault().Id) ? db.tabStocks.Where(x => x.ProductSKU == g.FirstOrDefault().ProductSKU && x.SourceDocRef != g.FirstOrDefault().SourceDocRef && x.Id < g.OrderBy(t => t.Id).FirstOrDefault().Id).OrderByDescending(x => x.Id).FirstOrDefault().Bal - g.Sum(f => f.Qty).Value : (0 - g.Sum(f => f.Qty)).Value).Value,
TransactionRef = g.FirstOrDefault().TransactionRef,
CreatedBy = g.FirstOrDefault().CreatedBy,
CreationDate = g.FirstOrDefault().CreationDate,
SourceDocRef = g.FirstOrDefault().SourceDocRef,
InQty = 0,
transactionType = "Sale",
UnitCost = g.FirstOrDefault().UnitCost.Value,
Received = 0,
TotalValuation = 0,
});
foreach (var NewStk in GroupIt.AsEnumerable())
{
tabStock stk = new tabStock();
stk.ProductName = NewStk.ProductName;
stk.ProductSKU = NewStk.ProductSKU;
stk.Qty = NewStk.Qty;
stk.OutQty = NewStk.OutQty;
stk.Bal = NewStk.Bal;
stk.transactionType = NewStk.transactionType;
stk.TransactionRef = NewStk.TransactionRef;
stk.CreatedBy = NewStk.CreatedBy;
stk.CreationDate = NewStk.CreationDate;
stk.SourceDocRef = NewStk.SourceDocRef;
stk.InQty = NewStk.InQty;
stk.UnitCost = NewStk.UnitCost;
stk.Received = 0;
stk.TotalValuation = 0;
db.tabStocks.Add(stk);
}
foreach (var OldStk in tbs.AsEnumerable())
{
db.tabStocks.Remove(OldStk);
}
db.SaveChanges();
For some reason i have this error:
Unable to create a constant value of type
'Type'. Only primitive types or enumeration types are supported in this context
Can anyone help me point to what this could be. I have looked at a lot of others related, nothing seems to work.. toList(), AsEnumerable(). Where is my code wrong please.

How to assign stored procedure result to a entity inside select statement in entity framework

I want to assign GetMajorMileStone(projecttask.ProjectTaskId) result to MajorMilestone.
I tried but getting following error:
LINQ to Entities does not recognize the method
'System.Data.Objects.ObjectResult1[.Poco.GetMajorMileStone_Result]
GetMajorMileStone(System.Nullable1[System.Guid])' method, and this
method cannot be translated into a store expression.'
Here is my code:
public ProjectsPayload GetProjectSchedule(int projectid, bool includeArchived, DateTime startDate, DateTime endDate, int userId)
{
using (var db = new Entities())
{
try
{
db.CommandTimeout = 1200;
var query = from project in db.Project.Where(t => (t.Active || t.TempActive) && t.ProjectId == projectid)
join UP in db.User_X_Project on project.ProjectId equals UP.ProjectId
where (UP.UserId == userId && UP.Active)
orderby (project.Priority ?? int.MaxValue)
orderby (project.ProjectTitle)
select new
{
Project = project,
ProjectTask = from projecttask in project.ProjectTask.Where(t => t.Active && (
(includeArchived == true && t.TaskStatusId == (int?)TaskStatus.Archived) ||
(includeArchived == false && t.TaskStatusId != (int?)TaskStatus.Archived))
|| t.TaskStatusId != (int?)TaskStatus.Planned)
join schedule in project.ProjectTask.SelectMany(p => p.ProjectTaskSchedule) on projecttask.ProjectTaskId equals schedule.ProjectTaskId
join daily in db.ProjectTaskSchedule.SelectMany(p => p.DailyStatus) on schedule.ProjectTaskScheduleId equals daily.ProjectTaskScheduleId
where schedule.Active && daily.Active && projecttask.Active && schedule.ResourceId == userId && (
(EntityFunctions.TruncateTime(daily.Date) >= EntityFunctions.TruncateTime(startDate.Date) &&
EntityFunctions.TruncateTime(daily.Date) <= EntityFunctions.TruncateTime(endDate.Date))
)
orderby schedule.StartDate
select new
{
ProjectTask = projecttask,
ProjectTaskSchedule = from projecttaskschedule in projecttask.ProjectTaskSchedule.Where(t => t.Active && t.ResourceId == userId)
select new
{
ProjectTaskSchedule = projecttaskschedule,
DailyStatus = projecttaskschedule.DailyStatus.Where(t => t.Active),
},
CritiCality = from cr in db.CritiCality.Where(ts => ts.ProjectTaskId == projecttask.ProjectTaskId) select cr,
MMDetails = from mm in db.MMDetails.Where(ts => ts.ProjectTaskId == projecttask.ProjectTaskId) select mm,
MajorMilestone = db.GetMajorMileStone(projecttask.ProjectTaskId).FirstOrDefault(),
}
};
var materialized = query.AsEnumerable();
var result = materialized.Select(t => new ProjectsPayload
{
ProjectId = t.Project.ProjectId,
ProjectTitle = t.Project.ProjectTitle,
Priority = t.Project.Priority,
ProjectDescription = t.Project.ProjectDescription,
ProjectTask = t.Project.ProjectTask.Select(x => new ProjectTaskPayload
{
Duration = x.Duration,
Hours = x.Hours,
IsOngoing = x.IsOngoing,
IsSummaryTask = x.IsSummaryTask,
Priority = x.Priority,
ParentTaskId = x.ParentTaskId,
ProjectId = x.ProjectId,
ProjectTaskId = x.ProjectTaskId,
TaskAcceptanceId = x.TaskAcceptanceId,
TaskStatusId = x.TaskStatusId,
TaskTitle = x.TaskTitle,
TaskTypeId = x.TaskTypeId,
IsMileStone = x.IsMileStone,
IsTimeAwayTask = x.IsTimeAwayTask,
AutoSize = x.AutoSize,
IsArchivedTasksInSummary = x.IsArchivedTasksInSummary,
IsASAP = x.IsASAP,
IsAutoCompleteEnable = x.IsAutoCompleteEnable,
IsSharedDiffSchedules = x.IsSharedDiffSchedules,
LongDescription = x.LongDescription,
OwnerId = x.OwnerId,
ShowInSummaryTask = x.ShowInSummaryTask,
SubTypeID = x.SubTypeID,
MMDetails1 = x.MMDetails1.Select(MD => new MMDetailsPayload { MajorMilestoneId = MD.MajorMilestoneId, ProjectTaskId = MD.ProjectTaskId, MMDetailsId = MD.MMDetailsId, Slack = MD.Slack }),
ProjectTaskSchedule = x.ProjectTaskSchedule.Select(a => new ProjectsTaskSchedulePayload
{
ProjectTaskScheduleId = a.ProjectTaskScheduleId,
StartDate = a.StartDate,
EndDate = a.EndDate,
ProjectTaskId = a.ProjectTaskId,
ResourceId = a.ResourceId,
ArchiveEndDate = a.ArchiveEndDate,
ArchiveStartDate = a.ArchiveStartDate,
IsSharedTask = a.IsSharedTask,
TimeUnitId = a.TimeUnitId,
DailyStatus = a.DailyStatus.Select(Ds => new DailyStatusPayload
{
Active = Ds.Active,
ActualHours = Ds.ActualHours,
DailyStatusId = Ds.DailyStatusId,
Date = Ds.Date,
ProjectTaskScheduleId = Ds.ProjectTaskScheduleId,
IsCloseOutDay = Ds.IsCloseOutDay,
Priority = Ds.Priority
})
}).ToList(),
CritiCality = x.CritiCality.Select(c => new CriticalityPayload { CriticalityId = c.CriticalityId, CriticalityTypeId = c.CriticalityTypeId, ProjectTaskId = c.ProjectTaskId }).ToList(),
}).ToList()
}).FirstOrDefault();
return result;
}
catch (EntityException ex)
{
if (ex.Message == connectionException)
throw new FaultException(dbException);
else
throw new FaultException(ex.Message);
}
}
}
My result is like this, I want all entities(Criticality,MMDetails and MajorMileStone), Not only MajorMileStone
MajorMileStone Result
I separate multiple simple query for testing. Please try to execute below two query and check whether successful or not.
// First query to get project
var query1 = from project in db.Project.Where(t => (t.Active || t.TempActive) && t.ProjectId == projectid)
join UP in db.User_X_Project on project.ProjectId equals UP.ProjectId
where (UP.UserId == userId && UP.Active)
orderby (project.Priority ?? int.MaxValue)
orderby (project.ProjectTitle)
.Select new { project = project }.ToList();
// Second query to get projecttask from query1.project and execute store procedure
var query2 = from projecttask in query1.project.ProjectTask.Where(t => t.Active && (
(includeArchived == true && t.TaskStatusId == (int?)TaskStatus.Archived) ||
(includeArchived == false && t.TaskStatusId != (int?)TaskStatus.Archived)) ||
t.TaskStatusId != (int?)TaskStatus.Planned)
join schedule in query1.project.ProjectTask.SelectMany(p => p.ProjectTaskSchedule) on projecttask.ProjectTaskId equals schedule.ProjectTaskId
join daily in db.ProjectTaskSchedule.SelectMany(p => p.DailyStatus) on schedule.ProjectTaskScheduleId equals daily.ProjectTaskScheduleId
where schedule.Active && daily.Active && projecttask.Active && schedule.ResourceId == userId && (
(EntityFunctions.TruncateTime(daily.Date) >= EntityFunctions.TruncateTime(startDate.Date) &&
EntityFunctions.TruncateTime(daily.Date) <= EntityFunctions.TruncateTime(endDate.Date))
)
orderby schedule.StartDate
.Select new
{
MajorMilestone = db.GetMajorMileStone(projecttask.ProjectTaskId).FirstOrDefault(),
}.ToList();
Let me know it has result or not. In the meantime you can check this "Method cannot be translated into a store expression"
It has link to article about what not to do with linq. Nested Linq like this is best to avoid and better to split up the query. If it affects the execution time, it better to execute raw sql.

Improving speed of method after adding value from different table aspn.net

I've got two tables: Index and Codes
when one condition is true, I need to check whether the Index is still valid and for that I need to get EndDate of the code which is in Codes table (as I've got only id of code in Index table)
This is how I do that:
1) First I get all Codes that have ended already (approx 3k+ items)
var goods = _context.Codes.Select(a =>
new Codes
{
Loid = a.Loid,
Pid = a.Pid,
Code = a.Code,
Startdate = a.Startdate,
Enddate = a.Enddate
})
.Where(x => x.Enddate < DateTime.Now)
.ToList();
then I'm taking my Index and adding values there as well as CodeEnd from Codes list above:
query = _context.VpAbcIndex
.AsNoTracking()
.Select(e => new VpAbcIndex
{
Id = e.Id,
ParentName = e.ParentName ?? "!",
ParentEndDate = e.ParentEndDate,
ParentStartDate = e.ParentStartDate,
ParentCode = e.ParentCode,
ParentNote = e.ParentNote ?? "",
ParentStatus = e.ParentStatus,
ChildName = e.ChildName ?? "!",
ChildId = e.ChildId,
ChildEndDate = e.ChildEndDate,
ChildStartDate = e.ChildStartDate,
CodeEnd = (filter.Level == 0) ? goods
.FirstOrDefault( x => x.Code == e.ParentCode).Enddate :
(filter.Level == 1) ? goods
.FirstOrDefault(x => x.Code == e.ChildCode).Enddate :
(filter.Level == 2) ?
goods
.FirstOrDefault(x => x.Code == e.GrandChildCode).Enddate : null
})
;
}
That's approx 10k items. It doesn't seem that much however it takes quite a long time for them to appear in my browser. Am I doing something wrong? Is there a faster way to join these values?

Use linq to match up pairs of rows in a set

In the system I use modifications to data are received in pairs of rows old and new with a RowMod flag, for example deleted, added, updated and unchanged rows come through as:
RowID Data RowMod
Row1 "fish" ""
Row1 "fish" "D"
Row2 "cat" "A"
Row3 "fox" ""
Row3 "dog" "U"
Row4 "mouse" ""
I'd like to match these up using the RowID that each row has and get something like:
RowID OldData NewData RowMod
Row1 "fish" null "D"
Row2 null "cat" "A"
Row3 "fox" "dog" "U"
Row4 "mouse" "mouse" ""
class Program
{
static void Main(string[] args)
{
IEnumerable<DataRow> rows = new[]
{
new DataRow(1,"fish",""),
new DataRow(1,"fish","D"),
new DataRow(2,"cat","A"),
new DataRow(3,"fox",""),
new DataRow(3,"dog","U"),
new DataRow(4,"mouse","")
};
var result = rows
.GroupBy(x => x.Id)
.Select(g => new
{
Count = g.Count(),
Id = g.First().Id,
FirstRow = g.First(),
LastRow = g.Last()
}).Select(item => new
{
RowId = item.Id,
OldData = item.Count == 1 && item.FirstRow.RowMod != "" ? null : item.FirstRow.Data,
NewData = item.LastRow.RowMod == "D" ? null : item.LastRow.Data,
RowMod = item.LastRow.RowMod
});
//Or using query syntax
var result2 = from x in rows
orderby x.Id, x.RowMod
group x by x.Id into g
select new
{
RowId = g.First().Id,
OldData = g.Count() == 1 && g.First().RowMod != "" ? null : g.First().Data,
NewData = g.Last().RowMod == "D" ? null : g.Last().Data,
RowMod = g.Last().RowMod
};
// Test
Console.WriteLine("RowID\tOldData\tNewData\tRowMod");
foreach (var item in result)
{
Console.WriteLine("{0}\t'{1}'\t'{2}'\t'{3}'",item.RowId,item.OldData ?? "null",item.NewData ?? "null",item.RowMod);
}
}
}
public class DataRow
{
public int Id { get; set; }
public string Data { get; set; }
public string RowMod { get; set; }
public DataRow(int id, string data, string rowMod)
{
Id = id;
Data = data;
RowMod = rowMod;
}
}
Output:
RowID OldData NewData RowMod
1 'fish' 'null' 'D'
2 'null' 'cat' 'A'
3 'fox' 'dog' 'U'
4 'mouse' 'mouse' ''
I am not sure if this is the best way to achieve your requirement but this is what I have:-
var result = rows.GroupBy(x => x.RowId)
.Select(x =>
{
var firstData = x.FirstOrDefault();
var secondData = x.Count() == 1 ? x.First().RowMod == "A" ? firstData : null
: x.Skip(1).FirstOrDefault();
return new
{
RowId = x.Key,
OldData = firstData.RowMod == "A" ? null : firstData.Data,
NewData = secondData != null ? secondData.Data : null,
RowMod = String.IsNullOrEmpty(firstData.RowMod) && secondData != null ?
secondData.RowMod : firstData.RowMod
};
});
Working Fiddle.
Getting the two parts of the intended object can be done iteratively:
foreach(var rowId in myList.Select(x => x.RowId).Distinct())
{
//get the left item
var leftItem = myList.SingleOrDefault(x => x.RowId == rowId && String.IsNullOrWhiteSpace(x.rowmod);
//get the right item
var rightItem = myList.SingleOrDefault(x => x.RowId == rowId && !String.IsNullOrWhiteSpace(x.rowmod);
}
Your question doesn't specify how you create the second object. Is it a different class?
Either way, you can extrapolate from the above snippet that either item might be null if it doesn't exist in the original set.
All you need to do is use those found objects to create your new object.
While I love LINQ a lot, I don't think it is appropriate here as you want to buffer some values while iterating. If you do this with LINQ, it will be at best not performing well, at worst it will iterate the collection multiple times. It also looks way cleaner this way in my opinion.
IEnumerable<TargetClass> MapOldValues(IEnumerable<SourceClass> source)
{
var buffer = new Dictionary<string, string>();
foreach(var item in source)
{
string oldValue;
buffer.TryGetValue(item.RowId, out oldValue);
yield return new TargetClass
{
RowId = item.RowId,
OldData = oldValue,
NewData = (item.RowMod == "D" ? null : item.Data),
RowMod = item.RowMod };
// if the rows come sorted by ID, you can clear old values from
// the buffer to save memory at this point:
// if(oldValue == null) { buffer.Clear(); }
buffer[item.RowId] = item.Data;
}
}
if you then only want the latest updates, you can go with LINQ:
var latestChanges = MapOldValues(source).GroupBy(x => x.RowId).Select(x => x.Last());
I guess there are more elegant ways to do it, but this produces the output you expect:
public class MyClass
{
public int RowID { get; set; }
public string Data { get; set; }
public string RowMod { get; set; }
}
var result = (from id in myList.Select(x => x.RowID).Distinct()
let oldData = myList.Where(x => x.RowID == id).SingleOrDefault(x => x.RowMod.Equals("")) != null
? myList.Where(x => x.RowID == id).Single(x => x.RowMod.Equals("")).Data
: null
let newData = myList.Where(x => x.RowID == id).SingleOrDefault(x => !x.RowMod.Equals("")) != null
? myList.Where(x => x.RowID == id).Single(x => !x.RowMod.Equals("")).Data
: null
let rowMod = myList.Where(x => x.RowID == id).SingleOrDefault(x => !x.RowMod.Equals("")) != null
? myList.Where(x => x.RowID == id).Single(x => !x.RowMod.Equals("")).RowMod
: null
select new
{
RowID = id,
OldData = oldData,
NewData = rowMod == null ? oldData : rowMod.Equals("D") ? null : newData,
RowMod = rowMod
});
foreach (var item in result)
{
Console.WriteLine("{0} {1} {2} {3}", item.RowID, item.OldData ?? "null", item.NewData ?? "null", item.RowMod ?? "-");
}

Assign value to String Property based on integer Property value in Linq query

I have a linq query, and want to assign string value to a string property, which in dependent on another int property value. I have saved int value in database, and now want to get appropriate string value for the saved integer value. Below is my query..
var data = db.ProjectSetups.Select(c => new ProjectSetup
{
ProjectId = c.ProjectId,
Name = c.Name,
NameArabic = c.NameArabic,
StartDate = c.StartDate,
EndDate = c.EndDate,
Date = c.Date,
StringType = (c.Type.ToInt32() == 1 ? "Development" : "Rental").ToString(),
StringStatus = (c.Status == 1 ? "InProgress" :
c.Status == 2 ? "Completed" :
c.Status == 3 ? "Dividend" : "Closed"),
LandArea = c.LandArea,
SaleAmount = c.SaleAmount
}).ToList();
I got below error
The entity or complex type 'PMISModel.ProjectSetup' cannot be constructed in a LINQ to Entities query
var data = db.ProjectSetups.ToList();
data = data.Select(c => new ProjectSetup
{
ProjectId = c.ProjectId,
Name = c.Name,
NameArabic = c.NameArabic,
StartDate = c.StartDate,
EndDate = c.EndDate,
Date = c.Date,
StringType = (c.Type.ToInt32() == 1 ? "Development" : "Rental").ToString(),
StringStatus = (c.Status == 1 ? "InProgress" :
c.Status == 2 ? "Completed" :
c.Status == 3 ? "Dividend" : "Closed"),
LandArea = c.LandArea,
SaleAmount = c.SaleAmount
}).ToList();

Categories

Resources