I have the following ViewModel:
public class DayTaskListViewModel
{
public int Id { get; set; }
public string DateFormatted { get; set; }
public bool HasRegistrations { get; set; }
public bool HasStartedRegistrations { get; set; }
public string ItemName { get; set; }
public string WorkTypeName { get; set; }
public string Description { get; set; }
public string LocationName { get; set; }
public bool IsActive { get; set; }
public string UserName { get; set; }
public string StateStatus { get; set; }
public DateTime TodaysDate { get; set; }
public int WeekNumber { get; set; }
public int YearNumber { get; set; }
public string Msg { get; set; }
public string SignInUserName { get; set; }
public string UnitCode { get; set; }
public IEnumerable<Machinery> machineryList { get; set; }
public IEnumerable<Cleaning> cleaningList { get; set; }
}
In my controller I have this definition of the model to be sent to the view:
var model = (from a in _db.WorkTask.Where(y => y.TaskDate.Date == querytodaysDate.Date && y.IsActive == true && (y.IsPrivateUserName == null || y.IsPrivateUserName == currUserName))
join b in _db.WorkTaskLog.Where(x => (x.UserName == currUserName || x.UserName == null) && x.IsActive == true && x.StateStatusId < 4) on a.Id equals b.WorkTaskId into joinedT
from c in joinedT.DefaultIfEmpty()
select new DayTaskListViewModel
{
Id = a.Id,
DateFormatted = a.DateFormatted,
HasRegistrations = a.HasRegistrations,
HasStartedRegistrations = a.HasStartedRegistrations,
ItemName = a.ItemName,
WorkTypeName = a.WorkTypeName,
Description = a.Description,
IsActive = c.IsActive ? c.IsActive : false,
UserName = c.UserName ?? String.Empty,
StateStatus = c.StateStatus ?? "Klar",
WeekNumber = (int)currWeekNo,
YearNumber = (int)currYearNo,
Msg = "",
TodaysDate = (DateTime)todaysDate,
SignInUserName = currUserName,
LocationName = a.LocationName,
UnitCode = a.UnitCode,
//machineryList = _db.Machinery.ToList(),
//cleaningList = _db.Cleaning.ToList(),
}).ToList();
My problem is the following lines in the definition:
//machineryList = _db.Machinery.ToList(),
//cleaningList = _db.Cleaning.ToList(),
Everything works as expected, but as soon as I enable those 2 lines it breaks with null errors.
VS can compile, but it breaks runtime.
I think I see the problem, but I don't know how to solve it.
I want ALL fields in the ViewModel EXCEPT the 2 mentioned lines to be a list, and then the 2 lines to be separate lists independent of the majority.
I have tried all combinations of moving those lines around, but then VS complains.
An example from another controller is this:
DriveListViewModel model = new DriveListViewModel()
{
Drive = await _db.Drive
.Where(m => m.StatusId == 5 || m.StatusId == 1010 || m.StatusId == 1012)
.Where(m => m.LoadingComplete == null)
.Where(m => !m.UnitCode.Contains(excludeString))
.Include(s => s.DriveStatus)
.Include(d => d.Location)
.Include(f => f.Item)
.GroupBy(m => m.RegistrationNumber)
.Select(m => m.FirstOrDefault())
.OrderBy(m => m.DriverToLoad)
.ToListAsync(),
machineryList = await _db.Machinery.ToListAsync(),
cleaningList = await _db.Cleaning.ToListAsync(),
};
This works perfectly, but the former model definition as more complex, so basically, I need something similar to the latter example separating the 2 lists from the other properties in the ViewModel.
Maybe this is VERY simple - however I'm struggling with it...
Anyone see the solution to this?
I don't think that you model is a list with so many includes.
I guess you really need this ViewModel
public class ViewModel
{
public List<DayTaskListViewModel> DayTaskListViewModelList {get; set;}
public List<Machinery> MachineryList {get; set;}
public List<Cleaning> CleaningList {get; set;}
}
code
var dayTaskListViewModel= (from ....
.....
select new DayTaskListViewModel
{
Id = a.Id,
.......
}).ToList(); // or ToListAsync too?
var model = new ViewModel
{
DayTaskListViewModel = dayTaskListViewModel,
MachineryList = _db.Machinery.ToList(),
CleaningList = _db.Cleaning.ToList()
}
// or if you can or prefer , use async
MachineryList = await _db.Machinery.ToListAsync(),
CleaningList = await _db.Cleaning.ToListAsync(),
Here is a snip of the view:
Top:
#model List<Day.Models.ViewModels.DayTaskListViewModel>
#using Day.Extensions
Looping through all properties:
if (Model.Count > 0)
{
foreach (var item in Model)
{
<input name="description" class="form-input" id="description" type="text" value="#item.Description">
..Several input fields...
}
}
Works fine.
Then I need to include select fields using the machineryList from the ViewModel:
<select name="machinery" asp-items="#Model.machineryList.ToSelectListItem((int)defaultMachinery)"></select>
Related
I'm trying group a collection of data by it's State but I'm stuck on the correct way to do this:
FileStateInfoDto
public class FileStateInfoDto : EntityDto<int>
{
public string StateName { get; set; }
public int StateNumber { get; set; }
public int FilesByStateCount { get; set; }
}
FileGroupDto
public class FileGroupDto : EntityDto<int>
{
public int CaseId { get; set; }
public string Name { get; set; }
public string ResourceKey { get; set; }
public bool IsFolder { get; set; }
public int SequenceNumber { get; set; }
public IList<FileStateInfoDto> FileStateInfo { get; set; }
public IList<FileGroupDto> FileGroups { get; set; }
public IList<FileInfoDto> Files { get; set; }
}
Here is the code I have:
return await Context.FileGroups
.Include(g => g.Case).Include(g => g.FileGroups).Include(g => g.Files)
.Where(g => g.Id == fileGroupId &&
g.CaseId == caseId &&
g.Case.CaseState != CaseState.Approved &&
g.Case.CaseState != CaseState.Submitted &&
(g.Case.CaseState != CaseState.Draft || g.Case.CreatorUserId == userId))
.OrderBy(g => g.SequenceNumber)
.Select(g => new FileGroup
{
Id = g.Id,
CaseId = g.CaseId,
Name = g.Name,
ResourceKey = g.ResourceKey,
IsFolder = g.IsFolder,
SequenceNumber = g.SequenceNumber,
FileGroups = g.FileGroups,
FileStateInfo = g.Files.GroupBy(f => f.State), <-- My problem
Files = g.Files.Where(f => f.IsActive && f.State != FileApprovalState.Approved).Select(
f => new File
{
Id = f.Id,
CreationTime = f.CreationTime,
CreatorUserId = f.CreatorUserId,
Title = f.Title,
FileName = f.FileName,
URL = f.URL,
Size = f.Size,
KeepOnPortal = f.KeepOnPortal,
CreatorUserName = Context.Users.FirstOrDefault(u => u.Id == (f.CreatorUserId ?? 0)).UserName,
CreatorUserRole = Context.CasePersons.Where(p => p.CaseId == caseId && p.UserId == f.CreatorUserId).Take(1).Select(p => p.CaseRoleType.Title).FirstOrDefault()
}
).ToList()
}).FirstOrDefaultAsync();
I'm trying to figure out how I should write this line FileStateInfo = g.Files.GroupBy(f => f.State) so it will give the expected result as below.
FileStateInfo = [{"StateName":"Approved","StateNumber":1, "FilesByStateCount":22},
{"StateName":"NotApproved","StateNumber":2, "FilesByStateCount":11}]
The State in g.Files.GroupBy(f => f.State) is an enum that contains Approved and NotApproved
StateName = Name of the State.
StateNumber = The Integer assinged.
FilesByStateCount = The files count by this state.
I hope it's possible because I've been trying to make this for a few days now.
I've tried things like this Post
I am having a class like this.
public class CameraModel
{
public int JobId { get; set; }
public int ViewId { get; set; }
public Guid ViewGuid { get; set; }
public string Name { get; set; }
public int ViewNum { get; set; }
public int LayoutID { get; set; }
public List<CameraViewItemModel> CameraViewItems { get; set; }
}
The CameraViewItemModel class is like this:
public class CameraViewItemModel
{
public int JobID { get; set; }
public Guid ViewGuid { get; set; }
public int ViewID { get; set; }
public int CamNum { get; set; }
public Guid ChannelGuid { get; set; }
public string Name { get; set; }
public ActionType Action { get; set; }
}
Now, I am assigning the list of CameraViewItemModel like this:
// get all the cameramodel's
cameraModels = _unitOfWork.Context.CameraViews.Where(m => m.JobId == siteId)
.Select(m => new CameraModel
{
JobId = m.JobId,
ViewId = m.ViewId,
ViewGuid = m.ViewGuid,
Name = m.Name,
ViewNum = m.ViewNum,
LayoutID = m.LayoutId
}).ToList();
// get all the cameraviewitemmodels
cameraViewItemModels =
(from cameraView in _unitOfWork.Repository<CameraViews>().Get(x => x.JobId == siteId).Result
join cameraViewItem in _unitOfWork.Repository<CameraViewItems>().Get(x => x.JobId == siteId)
.Result on cameraView.ViewId equals cameraViewItem.ViewId into CameraViewItemResults
from cameraViewItemResult in CameraViewItemResults.DefaultIfEmpty()
join cameraChannel in _unitOfWork.Repository<CameraChannels>().Get(x => x.JobId == siteId)
.Result on (cameraViewItemResult == null ? new Guid() : cameraViewItemResult.ChannelGuid) equals cameraChannel.ChannelGuid into CameraChannelResults
from cameraChannelResult in CameraChannelResults.DefaultIfEmpty()
select new CameraViewItemModel
{
JobID = cameraView.JobId,
ViewID = cameraView.ViewId,
ViewGuid = cameraView.ViewGuid,
CamNum = cameraViewItemResult.CamNum,
ChannelGuid = cameraChannelResult.ChannelGuid,
Name = cameraChannelResult.Name
}).ToList();
// then do a 'join' on JobId, ViewId and ViewGuid and assign the list of cameraviewitemmodels to cameraModels.
foreach (var cameraModel in cameraModels)
{
cameraModel.CameraViewItems = (from cameraViewItem in cameraViewItemModels
where cameraModel.JobId == cameraViewItem.JobID
&& cameraModel.ViewId == cameraViewItem.ViewID
&& cameraModel.ViewGuid == cameraViewItem.ViewGuid
select cameraViewItem).ToList();
}
return cameraModels;
There are three tables in database:
CameraViews, CameraViewItems, CameraChannels.
CameraViews is the main table. It is left joined with CameraViewItems and CameraChannels to get the desired result. There may not be any data in CameraViewItems and CameraChannels for a corresponding CameraView.
Is it possible to assign the list of CameraViewItemModels to CameraModels in a single linq statement.
Here is a simple way to add values to a sub list, dunno if this is what you mean. You can keep selecting sub lists if that is necessary.
var parent_lst = new List<List<string>>(); // Root/parent list that contains the other lists
var sub_lst = new List<string>(); // Sub list with values
var selected_parent_lst = parent_lst[0]; // Here I select sub list, in this case by list index
selected_parent_lst.Add("My new value"); // And here I add the new value
I'm a bit new to asp.net core. In this query, it keeps on requerying the db on every node to map from OrgStructures to ToOrgStructureModel is there a way we can make this more efficient:
This is the area where it keeps on requerying the db: .Select(org => org.ToOrgStructureModel(db.OrgStructures.Where(s => s.ParentNodeId == org.NodeId).Count() > 0))
Whole query:
public virtual IList<OrgStructureModel> GetAll()
{
using (var db = _context)
{
var result = db.OrgStructures
.Where(e => e.FiscalYear == 19)
.Select(org => org.ToOrgStructureModel(db.OrgStructures.Where(s => s.ParentNodeId == org.NodeId).Count() > 0))
.ToList();
_session.SetObjectAsJson("OrgStructure", result);
return result;
}
}
ToOrgStructureModel:
public static OrgStructureModel ToOrgStructureModel(this OrgStructure org, bool hasChildren)
{
return new OrgStructureModel
{
NodeId = org.NodeId,
ParentNodeId = org.ParentNodeId,
Name = org.Name,
DepartmentCode = org.DepartmentCode,
Acronym = org.Acronym,
LegacyId = org.LegacyId,
hasChildren = hasChildren
};
}
OrgStructureModel:
public class OrgStructureModel
{
[ScaffoldColumn(false)]
public int? NodeId { get; set; }
[Required]
public string Name { get; set; }
public string Acronym { get; set; }
public string DepartmentCode { get; set; }
public int? ParentNodeId { get; set; }
public int? LegacyId { get; set; }
public int FiscalYear { get; set; }
public int DepartmentId { get; set; }
[ScaffoldColumn(false)]
public bool hasChildren { get; set; }
public OrgStructure ToEntity()
{
return new OrgStructure
{
NodeId = NodeId,
Name = Name,
Acronym = Acronym,
ParentNodeId = ParentNodeId,
DepartmentCode = DepartmentCode,
LegacyId = LegacyId,
FiscalYear = FiscalYear,
DepartmentId = DepartmentId
};
}
}
Avoid using custom methods when using Linq-to-sql.
Here's a working alternative that doesn't use ToOrgStructureModel method:
var result = db.OrgStructures
.Where(e => e.FiscalYear == 19)
.Select(org => new OrgStructureModel
{
NodeId = org.NodeId,
ParentNodeId = org.ParentNodeId,
Name = org.Name,
DepartmentCode = org.DepartmentCode,
Acronym = org.Acronym,
LegacyId = org.LegacyId,
// Notice using "Any" method instead of comparing count with 0
hasChildren = db.OrgStructures.Any(s => s.ParentNodeId == org.NodeId),
})
.ToList();
You are creating a lot of queries, essentially for every record that it will pull out it will query one more time for each of them to check for hasChildren.
Include the link to the child in your main model (if it's a collection make it a collection),
public class OrgStructureModel
{
...
public int? ChildId {get;set;}
public OrgStructureModel Child {get;set;}
}
And then you can create a check in the query
var result = db.OrgStructures
.Where(e => e.FiscalYear == 19 && e.ChildId != null)
.Select(org => org.ToOrgStructureModel())
.ToList();
Also read this blog post on projection.
I am trying to determine the Distinct count for a particular field in a collection of objects.
private static RemittanceCenterBatchSummaryListModel SummarizeFields(RemittanceCenterSummaryListModel remittanceCenterSummaryListModel)
{
var result = remittanceCenterSummaryListModel.RemittanceBatchSummaryRecord.GroupBy(x => new{x.FileId, x.SourceFileName, x.BatchCode, x.BatchType})
.Select(x => new RemittanceCenterBatchSummarizedModel()
{
FileId = x.Key.FileId,
SourceFileName = x.Key.SourceFileName,
BatchCode = x.Key.BatchCode,
BatchType = x.Key.BatchType,
DetailRecordCountAdc = x.Count(y => y.BillingSystemCode == BillingSystemCode.Adc),
DetailRecordCountNotAdc = x.Count(y => y.BillingSystemCode == BillingSystemCode.Exd),
AmountAdc = x.Where(y => y.BillingSystemCode == BillingSystemCode.Adc).Sum(y => y.PaymentAmount),
AmountNotAdc = x.Where(y => y.BillingSystemCode == BillingSystemCode.Exd).Sum(y => y.PaymentAmount),
UniqueFileCount = x.Select(y => x.Key.FileId).Distinct().Count()
});
return CreateSummaryListModel(result);
}
Input entities:
public class RemittanceCenterSummaryListModel
{
public RemittanceCenterSummaryListModel()
{
this.RemittanceBatchSummaryRecord = new List<RemittanceBatchProcessingModel>();
}
public List<RemittanceBatchProcessingModel> RemittanceBatchSummaryRecord { get; private set; }
}
public class RemittanceCenterBatchSummarizedModel
{
public string FileId { get; set; }
public string SourceFileName { get; set; }
public string BatchCode { get; set; }
public string BatchType { get; set; }
public int DetailRecordCountAdc { get; set; }
public int DetailRecordCountNotAdc { get; set; }
public int DetailRecordCountTotal { get; set; }
public decimal AmountAdc { get; set; }
public decimal AmountNotAdc { get; set; }
public decimal AmountTotal { get; set; }
public BillingSystemCode BillingSystemCode { get; set; }
public int UniqueFileCount { get; set; }
}
private static RemittanceCenterBatchSummaryListModel CreateSummaryListModel(IEnumerable<RemittanceCenterBatchSummarizedModel> summaryModels)
{
var summaryModelList = new RemittanceCenterBatchSummaryListModel();
foreach (var summaryRec in summaryModels)
{
var summaryModel = new RemittanceCenterBatchSummarizedModel
{
FileId = summaryRec.FileId,
SourceFileName = summaryRec.SourceFileName,
BatchCode = summaryRec.BatchCode,
BatchType = summaryRec.BatchType,
DetailRecordCountAdc = summaryRec.DetailRecordCountAdc,
DetailRecordCountNotAdc = summaryRec.DetailRecordCountNotAdc,
AmountAdc = summaryRec.AmountAdc,
AmountNotAdc = summaryRec.AmountNotAdc,
UniqueFileCount = summaryRec.UniqueFileCount
};
summaryModelList.RemittanceBatchSummary.Add(summaryModel);
}
return summaryModelList;
}
Example input records:
Record1:
FileId: '123'
SourceFileName: 'test.file.txt'
BatchCode: 'aaa'
BatchType: 'scanned'
PaymentAmount: '50.00'
BillingSystemCode: 'Adc'
Record1:
FileId: '1234'
SourceFileName: 'test.file2.txt'
BatchCode: 'aab'
BatchType: 'scanned'
PaymentAmount: '52.00'
BillingSystemCode: 'Adc'
ActualOuput for UniqueFileCount Field:
UniqueFileCount = 1
ExpectedOutput results for UniqueFileCount Field:
UniqueFileCount = 2
What am I doing wrong?
It sounds like you want the distinct count of FileId for the entire collection and not just for each group, which will always be 1 since FileId is one of the fields you group on. If that is the case then you can just calculate that count first
int distinctFileIds = remittanceCenterSummaryListModel.RemittanceBatchSummaryRecor‌​d
.Select(x => x.FileId)
.Distinct()
.Count();
Then use that in your Linq query
UniqueFileCount = distinctFileIds
I have the following entities (I18N is a localized entity):
public class Post {
public Int32 Id { get; set; }
public Boolean IsPublished { get; set; }
public List<PostI18N> PostsI18N { get; set; }
public List<Tag> Tags { get; set; }
public Author { get; set; }
}
public class Tag {
public List<TagI18N> TagsI18N { get; set; }
}
public class Author {
public Int32 Id { get; set; }
public String Name { get; set; }
}
public class PostI18N {
public Int32 Id { get; set; }
public String Text { get; set; }
public String Title { get; set; }
}
public class TagI18N {
public Int32 Id { get; set; }
public String Name { get; set; }
}
I need to get all information of 4 posts so I tried to flatten the query:
var posts = await _context
.Posts
.SelectMany(x => x.PostsI18N, (Post, PostI18N) =>
new { Post, PostI18N, Post.Tags, Post.Author })
.Where(x => x.PostI18N.Language == "en")
.Select(x => new PostDTO {
Id = x.Post.Id,
Title = x.PostI18N.Title,
Text = x.PostI18N.Text,
AuthorName = x.Author.Name
TagsNames = // Names taken from x.Tags.TagsI18N where TagsI18N
// language is "en" ... So, for each tag look the
// one Tag.TagI18N which Tag.TagI18N.Language = "en"
// and get Tag.TagI18N.Name
})
.Take(4)
.ToListAsync();
PROBLEM:
The problem is that I also need the TagsI18N flatten so I can take their names for English language ...
It this possible with SelectMany? How should I do this?
Try it in query syntax instead:
var posts = await (
from p in _context.Posts
from pn in p.PostsI18N
where pn.Language == "en"
select new PostDTO {
Id = p.Id,
Title = pn.Title,
Text = pn.Text,
AuthorName = p.Author.Name,
TagsNames = from t in p.Tags
from tn in t.TagsI18N
where tn.Language == "en"
select tn.Name
}).Take(4).ToListAsync();
The SelectMany syntax should work as well, but it gets a bit "nested":
var posts = await _context
.Posts
.SelectMany(x => x.PostsI18N, (Post, PostI18N) =>
new { Post, PostI18N, Post.Tags, Post.Author })
.Where(x => x.PostI18N.Language == "en")
.Select(x => new PostDTO {
Id = x.Post.Id,
Title = x.PostI18N.Title,
Text = x.PostI18N.Text,
AuthorName = x.Author.Name
TagsNames =
x.Tags.SelectMany(t => t.TagsI18N, (Tag, TagI18N) =>
new { Tag, TagI18N })
.Where(t => t.TagI18N.Language == "en")
.Select(t => t.TagI18N.Name)
})
.Take(4)
.ToListAsync();