AsEnumerable Dynamic Fields in Where & Select - c#

I want to use the distinct clause for multiple levels. Firstly i tried with DataTable but did't got success so i converted DataTable to AsEnumerable.
My problem here is that the Fields which i have specified/hard coded will be coming dynamic, same for both Where & Select.
How to add dynamic Fields in Where & Select?
DataTable data3 = new DataTable();
var listData = data3.AsEnumerable()
.Where(m => !String.IsNullOrEmpty(m.Field<string>("clientname"))
&& !String.IsNullOrEmpty(m.Field<string>("project"))
&& !String.IsNullOrEmpty(m.Field<string>("postedstate"))
&& !String.IsNullOrEmpty(m.Field<string>("postedcity"))
&& !String.IsNullOrEmpty(m.Field<string>("siteadd")))
.Select(row => new
{
clientname = row.Field<string>("clientname"),
project = row.Field<string>("project"),
postedstate = row.Field<string>("postedstate"),
postedcity = row.Field<string>("postedcity"),
siteadd = row.Field<string>("siteadd")
}).Distinct();

You could do something similar to this:
string clientName = "my client";
string project = null;
DataTable data3 = new DataTable();
var listData = data3.AsEnumerable().Where(m =>
(String.IsNullOrEmpty(clientName) || m.Field<string>("clientname") == clientName)
&& (String.IsNullOrEmpty(project) || m.Field<string>("project") == project)
).Select(row => new Project()
{
clientname = row.Field<string>("clientname"),
project = row.Field<string>("project"),
postedstate = row.Field<string>("postedstate"),
postedcity = row.Field<string>("postedcity"),
siteadd = row.Field<string>("siteadd")
}).Distinct();
This way you will have no need to have an anonymous type returned and get rid of the problem.

Related

Fill by default Select = null in linq

I have this sentence linq, with select inside a select using a two viewmodels, the problem is that
in my loginviewmodel not all have a status equal to received, there may be nulls, but when putting them in my view some columns in my grid appear empty, I would like to see N/A appear by default if logviewmodel is = null but I don't know how to do it, I return this as JSON since I'm using datatable on the server side, I don't know if manipulating the json can also be done
I Share my linq sentence
var result = db.document.Select(d => new DocumentViewModel
{
DocumentId = d.DocumentId,
Name = w.name
ReceivedLogs = d.Logs
.Where(l => l.Status == Status.Received)
.Select(l => new LogViewModel
{
CurrentApprover = l.User,
NameApprover = l.User.FullName
}).FirstOrDefault()
}).ToList();
thanks
You can check if FirstOrDefault() returns null and then use a default LogViewModel:
var result = db.document.Select(d => new DocumentViewModel
{
DocumentId = d.DocumentId,
Name = w.name
ReceivedLogs = d.Logs
.Where(l => l.Status == Status.Received)
.Select(l => new LogViewModel
{
CurrentApprover = l.User,
NameApprover = l.User.FullName
}).FirstOrDefault() ?? new LogViewModel {
CurrentApprover = "N/A",
NameApprover = "N/A"
}
}).ToList();

How to add object to in to List

I have following code,
public List<ActiveViewUser> GetAllActiveUsers(int branchId){
List<ActiveViewUser> status = new List<ActiveViewUser>();
DataSet ds = DataAccessManager.ExecuteStoredProcedure("spGetAllActiveUsers", parameters);
// add an all user option to the list
ActiveViewUser allusr = new ActiveViewUser();
List<ActiveViewUser> allActiveusers = new List<ActiveViewUser>();
allusr.UserId = -1;
allusr.UserName = "AllUsers";
allusr.FirstName = "All";
status.Add(allusr);
foreach (DataRow dr in ds.Tables[0].AsEnumerable())
{
ActiveViewUser usr = new ActiveViewUser();
usr.UserId = dr["UserId"].ToString().Length == 0
? 0
: Convert.ToInt32(dr["UserId"].ToString());
usr.UserName = dr["UserName"].ToString();
usr.FirstName = dr["FirstName"].ToString();
allActiveusers.Add(usr);
}
var newli = allActiveusers.OrderBy(x => x.FirstName).ToList();
status.Add(newli); //Error occurred in this line
}
As per the above code, I need to first insert All as the first index and, other all active users need insert after the that order by user's FirstName. So i tried above query. its returns following error.
cannot convert from 'System.Collections.Generic.List<Lib.DataView.ActiveViewUser>' to 'Lib.DataView.ActiveViewUser'. What did i do wrong here. how can I fix this?
Add requires a single element of the list type, now the code is trying to add a whole list (newli) instead of each single objects of that list.
This should insert, in the status list, all the elements of the newli list
status.AddRange(newli);
The List<T> class has also an InsertTo method that allows to insert an element to a specific position. So you could even simplify a bit the code with
status = new List<ActiveUser>();
foreach (DataRow dr in ds.Tables[0].AsEnumerable())
{
ActiveViewUser usr = new ActiveViewUser();
usr.UserId = dr["UserId"].ToString().Length == 0 ? 0 : Convert.ToInt32(dr["UserId"].ToString());
usr.UserName = dr["UserName"].ToString();
usr.FirstName = dr["FirstName"].ToString();
// Add directly to the status list....
status.Add(usr);
}
// Order the status list and reassign the result to the same list
status = status.OrderBy(x => x.FirstName).ToList();
// Finally insert at position 0 the "AllUsers" user.
status.InsertTo(0, new ActiveUser{UserId=-1, UserName="AllUsers", FirstName="All"}
return status;
You can try materialize (i.e. create) status with a help of Linq from top and body records:
// Top record(s)
var allusr = new ActiveViewUser[] {
new ActiveViewUser() {
UserId = -1,
UserName = "AllUsers",
FirstName = "All",
}
};
// Body records
var newli = DataAccessManager
.ExecuteStoredProcedure("spGetAllActiveUsers", parameters)
.Tables[0]
.AsEnumerable()
.Select(dr => new ActiveViewUser() {
UserId = dr["UserId"] == DBNull.Value ? 0 : Convert.ToInt32(dr["UserId"]),
UserName = Convert.ToString(dr["UserName"]),
FirstName = Convert.ToString(dr["FirstName"]),
})
.OrderBy(x => x.FirstName);
// Top and Body combined:
List<ActiveViewUser> status = allusr
.Concat(newli)
.ToList();

linq query for sql xml column

I would need to write a linq query in c# for the following sql query.
I have no issues in implementing where, not in, orderby and descending but the problem is to query a sql xml column
SELECT [ID]
,[QueuedTime]
,Parameters.query('data(Root/Root/#type)').value('.', 'varchar(500)') as CommandName //how to implement this line in linq
,[Status]
,[CurrentRetryCount]
,[MaxRetryCount]
,[RetryDelaySeconds]
,[CompletedTime]
,[LastTriedTime]
,[LastError]
,Parameters
,[PrincipalString]
FROM [AppServer].[dbo].[RequestQueue]
where interfacename = 'ICommunicationsService'
and MethodName = 'ProcessCommand'
and status not in (1,2)
order by id desc
The following query will meet where, not in and order by descending conditions. I am concerned about how do I implement
'Parameters.query('data(Root/Root/#type)').value('.', 'varchar(500)') as CommandName' in linq
var unwantedStatus = new[] { 1, 2 };
var operationTimedOutTasks = context.TblRequestQueues
.Where(t => t.MethodName == "ProcessCommand" && !unwantedStatus.Contains(t.Status))
.OrderByDescending(t => t.ID)
.ToList();
The following has resolved my issue.
var query = from queue in context.TblRequestQueues
where queue.MethodName == methodName
&& queue.InterfaceName == interfaceName
&& !unwantedStatus.Contains(queue.Status)
orderby queue.ID descending
select new
{
queue.QueuedTime,
queue.Parameters,
queue.Status,
queue.CurrentRetryCount,
queue.MaxRetryCount,
queue.RetryDelaySeconds,
queue.CompletedTime,
queue.LastTriedTime,
queue.LastError,
queue.PrincipalString
};
var operationTimedOutTasks = query.AsEnumerable()
.Select(t => new TblRequestQueueDto
{
QueuedTime = t.QueuedTime,
Parameters = t.Parameters,
CommandName = XDocument.Parse(t.Parameters).Element("Root").Descendants("Root").FirstOrDefault().Attribute("type").Value,
Status = t.Status,
CurrentRetryCount = t.CurrentRetryCount,
MaxRetryCount = t.MaxRetryCount,
RetryDelaySeconds = t.RetryDelaySeconds,
CompletedTime = t.CompletedTime,
LastTriedTime = t.LastTriedTime,
LastError = t.LastError,
PrincipalString = t.PrincipalString
}).ToList();
Try with XDocument. (using System.Xml.Linq;)
Example:
var operationTimedOutTasks = (from queue in context.TblRequestQueues
where queue.MethodName == "ProcessCommand"
&& !unwantedStatus.Contains(t.Status)
let xml = XDocument.Parse(queue.Parameters)
orderby queue.ID
select new
{
//Other columns
Parameters = xml.Descendants("Root").FirstOrdDefault().Attribute("type").Value
}).ToList();

What can be used instead of Datatable in LINQ

I have a SQL query that returns a Datatable:
var routesTable = _dbhelper.Select("SELECT [RouteId],[UserId],[SourceName],[CreationTime] FROM [Routes] WHERE UserId=#UserId AND RouteId=#RouteId", inputParams);
and then we can work with Datatable object of routesTable
if (routesTable.Rows.Count == 1)
{
result = new Route(routeId)
{
Name = (string)routesTable.Rows[0]["SourceName"],
Time = routesTable.Rows[0]["CreationTime"] is DBNull ? new DateTime() : Convert.ToDateTime(routesTable.Rows[0]["CreationTime"])
};
result.TrackPoints = GetTrackPointsForRoute(routeId);
}
I want to change this code to linq but I don't know how can I simulate Datatable in LINQ ,I wrote this part:
Route result = null;
aspnetdbDataContext aspdb = new aspnetdbDataContext();
var Result = from r in aspdb.RouteLinqs
where r.UserId == userId && r.RouteId==routeId
select r;
....
but I don't know how can I change this part:
if (routesTable.Rows.Count == 1)
{
result = new Route(routeId)
{
Name = (string)routesTable.Rows[0]["SourceName"],
Time = routesTable.Rows[0]["CreationTime"] is DBNull ? new DateTime() : Convert.ToDateTime(routesTable.Rows[0]["CreationTime"])
};
would you please tell me how can I do this?
EDIT
here you can see the whole block of code in original
public Route GetById(int routeId, Guid userId)
{
Route result = null;
var inputParams = new Dictionary<string, object>
{
{"UserId", userId},
{"RouteId", routeId}
};
var routesTable = _dbhelper.Select("SELECT [RouteId],[UserId],[SourceName],[CreationTime] FROM [Routes] WHERE UserId=#UserId AND RouteId=#RouteId", inputParams);
if (routesTable.Rows.Count == 1)
{
result = new Route(routeId)
{
Name = (string)routesTable.Rows[0]["SourceName"],
Time = routesTable.Rows[0]["CreationTime"] is DBNull ? new DateTime() : Convert.ToDateTime(routesTable.Rows[0]["CreationTime"])
};
result.TrackPoints = GetTrackPointsForRoute(routeId);
}
return result;
}
SELECT Function:
public DataTable Select(string query, Dictionary<string, object> parameters)
{
var dt = new DataTable();
using (_command = new SqlCommand(query, _connnection))
{
InitializeParametersAndConnection(parameters);
using (_adapter = new SqlDataAdapter(_command))
{
_adapter.Fill(dt);
}
}
return dt;
}
and the GetTrackPointsForRoute
private List<TrackPoint> GetTrackPointsForRoute(int routeId)
{
aspnetdbDataContext aspdb = new aspnetdbDataContext();
var result = new List<TrackPoint>();
var trackPointsTable = from t in aspdb.TrackPointlinqs
where t.RouteFK == routeId
select t;
foreach (var trackPointRow in trackPointsTable)
{
var trackPoint = new TrackPoint
{
Id = (int)trackPointRow.TrackPointId,
Elevation = Convert.ToSingle(trackPointRow.Elevation),
Latitude = Convert.ToDouble(trackPointRow.Latitude),
Longitude = Convert.ToDouble(trackPointRow.Longitude),
Time = trackPointRow.TrackTime is DBNull ? new DateTime() : (DateTime)trackPointRow.TrackTime
};
result.Add(trackPoint);
}
return result;
}
var firstRoute = aspdb.RouteLinqs
.Where(r => r.UserId == userId && r.RouteId == routeId)
.FirstOrDefault();
if (firstRoute == null)
{
return null;
}
else
{
return new Route(routeId)
{
Name = first.SourceName,
Time = first.CreationTime ?? new DateTime(),
TrackPoints = GetTrackPointsForRoute(routeId)
};
}
If this is LINQ to SQL you can simplify it further (this won't work with LINQ to Entity Framework though):
return aspdb.RouteLinqs
.Where(r => r.UserId == userId && r.RouteId == routeId)
.Select(r => new Route(routeId)
{
Name = r.SourceName,
Time = r.CreationTime ?? new DateTime(),
TrackPoints = GetTrackPointsForRoute(routeId)
})
.FirstOrDefault();
Note: You probably can replace GetTrackPointsForRoute with a join to the child table, meaning that the entire method can be done with a single call to the database, rather than one call to get the routes, and a second call to get the points. To do this you should learn about associations and joins in LINQ to SQL.

C# LINQ filtering

I have this piece of code
var tblGrouped = dtCSV.AsEnumerable()
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
});
But I want to add an additional column to filter by. Basically if course_type_id = 1 for example. dtCSV is the source where the course_type_id is populated. I tried the following but it didn't work:
var tblGrouped = dtCSV.AsEnumerable()
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
course_type_id = "1",
});
If I understand your requirement correctly, you want to group rows which have a course_type_id of 1?
var tblGrouped = dtCSV.AsEnumerable()
.Where(r => r.Field<String>("course_type_id") == "1")
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
});
To filter by use Where syntax
Ex. .Where(a=>a.Field<String>("course_type_id") == "1")
You'll want to add the condition first. You can do that using .Where:
var tblGrouped = dtCSV.AsEnumerable()
.Where(r => r.Field<String>("course_type_id") == "1")
.GroupBy(r => new
{
product_id = r.Field<String>("product_id"),
owner_org_id = r.Field<String>("owner_org_id"),
course_type_id = "1"
});

Categories