Creating Alias in LINQ with SelectMany - c#

I have a viewmodel like this:
public class FileInfo
{
private string _fileNo;
private string _fileName;
public string FileNo
{
get
{
return _fileNo;
}
set
{
_fileNo = value;
}
}
public string FileName
{
get
{
return _fileName;
}
set
{
_fileName = value;
}
}
}
I have a List DataList with data and FileNo may have duplications.
I can use below LINQ to get all data from DataList with condition like this:
List<FileInfo> ViewList = DataList.Where(x => !string.IsNullOrWhiteSpace(x.FileName))
.GroupBy(y => y.FileNo)
.SelectMany(z => z).ToList();
How of I get Alias name in the SelectMany and also .ToList() for above query, it should look something like this:
List<FileInfo> ViewList = DataList.Where(x => !string.IsNullOrWhiteSpace(x.FileName))
.GroupBy(y => y.FileNo)
.SelectMany(new {...NewFileName = "Row " + FileNo + FileName, NewFileNo = "No " + FileNo}).ToList();
Any pointers would be highly appreciated
Thanks

Try as below -
var ViewList =
DataList
.Where(x => string.IsNullOrWhiteSpace(x.FileName))
.GroupBy(y => new { FileNo = y.FileNo })
.SelectMany(x =>
x.Select(y => new
{
NewFileName = "Row " + y.FileNo + y.FileName,
NewFileNo = "No " + y.FileNo
}))
.ToList();

Related

Multi column lambda expression

Upon completeing the tutorial here:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
I currently use the following
userAccesses = userAccesses.Where(s => s.employeeDetail.employeeNumber.ToUpper().Contains(searchValue.ToUpper()));
However I'd like to concatenate the knownas / surname columns and then do the contains on the concatenated items.
Could anyone explain/suggest an example syntax?
This is what I've attempted below but I'm certain my syntax is incorrect.
userAccesses = userAccesses.Where(s => s.employeeDetail.employeeNumber + " " + s.employeeDetail.knownas + " " + s.employeeDetail.surname).Contains(searchValue);
Thanks for the response everyone, final working version is below.
userAccesses.Where(x => (x.employeeDetail.employeeNumber + x.employeeDetail.knownas + x.employeeDetail.surname).Contains(searchValue));
You should go to this direction
public class Employee
{
public string knownas { get; set; }
public string userName { get; set; }
}
public void Test()
{
List<Employee> employess = new List<Employee>();
string searchvalue = "test";
var listEmplyer = employess.Where(x => (x.userName + x.knownas).Contains(searchvalue));
}
You'll simply need to concatenate the string and call Contains on that string.
userAccesses
.Where(s => $"{s.employeeDetail.employeeNumber} {s.employeeDetail.knownas} {s.employeeDetail.surname}".Contains(searchValue))
If you need an enumerable of strings as the result of the expression, you can also choose to use the following:
userAccesses
.Select(s => $"{s.employeeDetail.employeeNumber} {s.employeeDetail.knownas} {s.employeeDetail.surname}")
.Where(s => s.Contains(searchValue))
Searching through concatenated column values is weird...
I'd suggest smth like this:
var filtered = userAccesses.Where(s => s.employeeDetail.employeeNumber.Contains(searchValue)
|| s.employeeDetail.knownas.Contains(searchValue)
|| s.employeeDetail.surname.Contains(searchValue));

Linq2Db and string.join()

I am using Linq2db in my big query with subqueries.
At the one place inside it, I want to use string.Join():
...
FullPath = string.Join(" -> ", GetPathQuery(db, c.Id).Select(pi => pi.Name))
...
But I have received an exception:
LinqException: 'Join(" -> ", value(RI.DAL.Categories.AdminCategoryPreviewDAL).GetPathQuery(value(RI.DAL.Categories.AdminCategoryPreviewDAL+<>c__DisplayClass4_0).db, c.Id).Select(pi => pi.Name))' cannot be converted to SQL.
I use Postgre SQL and it has the concat_ws function which is perfect for me. So I try to use it:
[Sql.Expression("concat_ws({1}, {0})")]
public static string JoinAsString(this IQueryable<string> query, string separator)
{
return string.Join(separator, query);
}
...
FullPath = GetPathQuery(db, c.Id).Select(pi => pi.Name).JoinAsString(" -> ")
...
But I was failed with the same exception.
The full source code of the GetPathQuery:
private IQueryable<CategoryPathItemCte> GetPathQuery(IStoreDb db, Guid categoryId)
{
var categoryPathCte = db.GetCte<CategoryPathItemCte>(categoryHierarchy =>
{
return
(
from c in db.Categories
where c.Id == categoryId
select new CategoryPathItemCte
{
CategoryId = c.Id,
ParentCategoryId = c.ParentId,
Name = c.Name,
SeoUrlName = c.SeoUrlName
}
)
.Concat
(
from c in db.Categories
from eh in categoryHierarchy.InnerJoin(ch => ch.ParentCategoryId == c.Id)
select new CategoryPathItemCte
{
CategoryId = c.Id,
ParentCategoryId = c.ParentId,
Name = c.Name,
SeoUrlName = c.SeoUrlName
}
);
});
return categoryPathCte;
}
can you try like this,
FullPath = string.Join(" -> ", GetPathQuery(db, c.Id).Select(pi => pi.Name).ToList());
More query friendly approach
GetPathQuery(db, c.Id).Select(pi => pi.Name)
.Aggregate(string.Empty, (results, nextString)
=> string.Format("{0} -> {1}", results, nextString));

How to Convert List<'a> to other object list?

i want result linq statement convert to other list in Web Api
var data = Base_Tables.db.Lines.Find(id).Owner_Line.OrderByDescending(x => x.ID)
.Select(x => new { x.ID, Caption = x.Name1 + " " + x.Name2 + " " + x.Name3 })
.ToList();
List<HistoryLine> historyList = data as List<HistoryLine>();
Class HistoryLine
public class HistoryLine
{
public long ID { get; set; }
public string Caption { get; set; }
}
How to Convert ? , if can't convert statement, any way to fix this problem ?
Simply select into the object you want instead of an anonymous type.
var data = Base_Tables.db.Lines
.Find(id).Owner_Line
.OrderByDescending(x => x.ID)
.Select(x => new HistoryLine {ID = x.ID, Caption = x.Name1 + " " + x.Name2 + " " + x.Name3})
.ToList();
data is now a List<HistoryLine>

C# Use delegate to replace if else code

I know this method is working well. However I reused most of the code and it looks ugly... It should be possible to remove the if else using delegate. Any thoughts?
public IHttpActionResult TimeDatawithUserandServer(string name, string group)
{
List<Model> res = new List<Model>();
//group 1 is Server type
if (group.Equals("1"))
{
var realName = name.Replace("-", ".");
IQueryable<Overalldata> UserData = db.Overalldatas.Where(x => x.Server.Equals(realName));
var groupedUserData = UserData.GroupBy(x => new {x.EventDate, x.User}).ToList();
res.AddRange(groupedUserData.Select(item => new Model()
{
Count = item.Count(),
Date = item.Key.EventDate.ToString("yyyy-MM-dd HH:mm:ss"),
Name = item.Key.User
}));
}
//group 2 is User type
else
{
IQueryable<Overalldata> Serverdata = db.Overalldatas.Where(x => x.User.Equals(name));
var groupServerData = Serverdata.GroupBy(x => new {x.EventDate, x.Server}).ToList();
res.AddRange(groupServerData.Select(item => new Model()
{
Count = item.Count(),
Date = item.Key.EventDate.ToString("yyyy-MM-dd HH:mm:ss"),
Name = item.Key.Server
}));
}
return Ok(res);
}
You could do it this way:
public IHttpActionResult TimeDatawithUserandServer(string name, string group)
{
var getName = group == "1"
? (Func<Overalldata, string>)(od => od.Server)
: (Func<Overalldata, string>)(od => od.User);
var realName = group == "1"
? name.Replace("-", ".")
: name;
var UserData = group == "1"
? db.Overalldatas.Where(x => x.Server == realName)
: db.Overalldatas.Where(x => x.User == realName);
var groupedData =
UserData
.ToArray()
.GroupBy(x => new { x.EventDate, Name = getName(x) })
.ToArray();
var res =
groupedData
.Select(item => new Model()
{
Count = item.Count(),
Date = item.Key.EventDate.ToString("yyyy-MM-dd HH:mm:ss"),
Name = item.Key.Name
})
.ToList();
return Ok(res);
}
Without Delegates
Your code can simply be refactored to following and relieved from repetition:
public IHttpActionResult TimeDatawithUserandServer(string name, string group)
{
List<Model> res = new List<Model>();
var groupedData = group.Equals("1") ? FetchServerData(name) : FetchUserData(name);
res.AddRange(groupedData.Select(item => new Model()
{
Count = item.Count(),
Date = item.Key.EventDate.ToString("yyyy-MM-dd HH:mm:ss"),
Name = item.Key.Server
}));
return Ok(res);
}
private GroupedDataType FetchServerData(string name)
{
var realName = name.Replace("-", ".");
var UserData = db.Overalldatas.Where(x => x.Server.Equals(realName));
return UserData.GroupBy(x => new {x.EventDate, x.User}).ToList();
}
private GroupedDataType FetchUserData(string name)
{
var Serverdata = db.Overalldatas.Where(x => x.User.Equals(name));
return Serverdata.GroupBy(x => new {x.EventDate, x.Server}).ToList();
}
Please replace the GroupedDataType with the appropriate type in the two methods above and in the code below.
With Delegates
Using Reflection we find the correct field (or property) and then compare the value as in the code below:
public IHttpActionResult TimeDatawithUserandServer(string name, string group)
{
List<Model> res = new List<Model>();
var groupedData = GetGroupedList(group, name);
res.AddRange(groupedData.Select(item => new Model()
{
Count = item.Count(),
Date = item.Key.EventDate.ToString("yyyy-MM-dd HH:mm:ss"),
Name = item.Key.Server
}));
return Ok(res);
}
private static IEnumerable<GroupedDataType> GetGroupedList(string group, string name)
{
var filteredList = db.Overalldatas.Where(dbData => Filter(dbData, group, name));
return filteredList.GroupBy(x => new {x.EventDate, x.User}).ToList();
}
private static readonly Func<ODType, string, string, bool> Filter = (ode, group, name) =>
{
var objType = overallDataElement.GetType();
var field = objType.GetMember(group)[0];
return (field != null)
&& ((FieldInfo) field).GetValue(ode).ToString().Equals(name);
};
ODType is Type of the elements in of Overalldatas list and ode is overalldata list's one single element.
I agreed with a comment made by lc who suggested running this through a code review.
There are some potential anti-patterns in your code
The group parameter is an example of control coupling
The control coupling is utilized via the if statement. For me, this is a clear sign that the method should be broken into separate methods.
I would also like to call attention to the Overalldatas collection. It's name is suspicious which leads to other questions including "Is this data object trying to do too much?". But I won't really touch and this as it's less relevant to your question and my answer.
That said, my answer is that you should have two methods, one for "Server Type" and one for "User Type". I realize this pushes that "group" check elsewhere, but that can be solved later and today the intent of your methods will be MUCH clearer.
public IHttpActionResult TimeDataByUserName(string userName)
{
List<Model> res = new List<Model>();
IQueryable<Overalldata> Serverdata = db.Overalldatas.Where(x => x.User.Equals(userName));
var groupServerData = Serverdata.GroupBy(x => new {x.EventDate, x.Server}).ToList();
res.AddRange(groupServerData.Select(item => new Model()
{
Count = item.Count(),
Date = item.Key.EventDate.ToString("yyyy-MM-dd HH:mm:ss"),
Name = item.Key.Server
}));
return Ok(res);
}
public IHttpActionResult TimeDataByServerName(string serverName)
{
List<Model> res = new List<Model>();
IQueryable<Overalldata> UserData = db.Overalldatas.Where(x => x.Server.Equals(serverName));
var groupedUserData = UserData.GroupBy(x => new {x.EventDate, x.User}).ToList();
res.AddRange(groupedUserData.Select(item => new Model()
{
Count = item.Count(),
Date = item.Key.EventDate.ToString("yyyy-MM-dd HH:mm:ss"),
Name = item.Key.User
}));
}

How to compare and select values from string using Linq?

Had a class:
class filedate
{
public int id;
public string fname;
}
Fill my list with values:
List<filedate> List = ReadList(sqlFiles);
string[] FolderFiles = System.IO.Directory.GetFiles(path2Copy);
Trying to get results:
var results = List.Where(filedate =>
FolderFiles.Any(x=>Path.GetFileNameWithoutExtension(x) ==
Path.GetFileNameWithoutExtension(filedate.fname)));
I have the same files in List and FolderFiles, but get no results in results. I am a newbie to Linq. Where is the problem?
update:
List: (count) > 1000
for example:
<1023, 'tr_F2opervag_2808_1644.dat'>
FolderFiles example:
"\\domain.corp.dns\share\folder\tr_F2opervag_2808_1644.dat"
Update 2:
found out my mistake! Comment with intersection was helpful! This code is working:
var results = List.Where(
(filedate x) =>
{
return ! FolderFiles.Any(xxx =>
Path.GetFileNameWithoutExtension(xxx) ==
Path.GetFileNameWithoutExtension(x.fname));
});
You're code works fine for me so there's something wrong with the format of your data in the List coming back from the database.
Post an example of an fname value from the filedata object. It needs to be a valid fully qualified path.
This works fine for me.
public class FileData{
public int id;
public string fname;
}
void Main()
{
List<FileData> list = new List<FileData>{
new FileData { id=1, fname="C:\\install.res.1042.dll"},
new FileData { id=2, fname="C:\\install.res.1041.dll" },
new FileData { id=3, fname="C:\\install.res.9999.dll"}
};
string[] FolderFiles = System.IO.Directory.GetFiles("C:\\");
var results = list
.Where(fd =>
FolderFiles.Any(x=>Path.GetFileNameWithoutExtension(x) ==
Path.GetFileNameWithoutExtension(fd.fname)));
Console.WriteLine(results);
}
If you need to find the difference this should work. This is available via Enumerable.Except.
var dbFiles = ReadList(sqlFiles);
var dbFilePaths =
dbFiles.Select(fdate =>
Path.GetFileNameWithoutExtension(fdate.fname).ToLower());
var fsFilePaths =
Directory
.GetFiles(path2Copy)
.Select(filePath =>
Path.GetFileNameWithoutExtension(filePath).ToLower());
var diff =
dbFilePaths
.Except(fsFilePaths)
.Join(dbFiles,
filePath => filePath,
fdate => fdate.fname,
(filePath, fdate) => fdate)
.ToList();

Categories