LINQ orderby int array index value - arrays

Using LINQ I would like to sort by the passed in int arrays index.
So in the code below attribueIds is my int array. I'm using the integers in that array for the where clause but I would like the results in the order that they were in while in the array.
public List BuildTable(int[] attributeIds)
{
using (var dc = new MyDC())
{
var ordering = attributeIds.ToList();
var query = from att in dc.DC.Ecs_TblAttributes
where attributeIds.Contains(att.ID)
orderby(ordering.IndexOf(att.ID))
select new Common.Models.Attribute
{
AttributeId = att.ID,
DisplayName = att.DisplayName,
AttributeName = att.Name
};
return query.ToList();
}
}

I would recommend selecting from the attributeIDs array instead. This will ensure that your items will be correctly ordered without requiring a sort.
The code should go something like this:
var query =
from id in attributeIds
let att = dc.DC.Ecs_TblAttributes.FirstOrDefault(a => a.ID == id)
where att != null
select new Common.Models.Attribute
{
AttributeId = att.ID,
DisplayName = att.DisplayName,
AttributeName = att.Name
};

Why don't you join:
public List BuildTable(int[] attributeIds)
{
using (var dc = new MyDC())
{
var query = from attID in attributeIds
join att in dc.DC.Ecs_TblAttributes
on attID equals att.ID
select new Common.Models.Attribute
{
AttributeId = attID,
DisplayName = att.DisplayName,
AttributeName = att.Name
};
return query.ToList();
}
}

Related

Linq EF6 adding multiple columns in a table from a list - Skips even rows

My application is MVC 5; I am trying to add multiple columns form a list into a table using:
var mylist = itemsToUpdate.Select(item => new
{
FirstName = item.FirstName,
LastName = item.LastName,
SNumber = item.SNumber
}).ToList();
foreach (var item in mylist)
{
var notification = new NotificationOld
{
FirstName = item.FirstName,
LastName = item.LastName,
SNumber = item.SNumber
};
db.NotificationOlds.Add(notification);
}
await db.SaveChangesAsync();
I get duplicates of row missing even number rows.
UPDATE:
The issue was in how I developed my SQL view by using:
ROW_NUMBER() OVER(ORDER BY dbo.LearnersOld.ID) AS SNumber

Do I have to loop through an IEnumerable return from Dapper even though I only return a single object?

I'm using Dapper to retrieve employee information when I select that employee from a list. Everything maps correctly, and then the rows are grouped according to employee.id. Just what I want. But Dapper returns an IEnumerable, which makes sense when I query for multiple employees and have to make multiple objects; but it makes less sense when I'm only returning the one. Is there a solution to this, or do I just need to loop through the single item? Here's my code:
public async Task<List<EmployeeModel>> GetSelectedEmployee(int selectedEmployeeID)
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(GlobalConfig.CnnString("WorkDeskDB")))
{
var par = new
{
SelectedEmployeeID = selectedEmployeeID
};
var sql = #"SELECT e.id, e.FirstName, e.LastName, e.Nickname,
em.EmployeeID, em.Address, em.Type,
e.JobTitleID, jt.id, jt.Name,
p.EmployeeID, p.Number, p.Type,
ect.EmployeeID, ect.NameID, ect.InitialDate, ect.ExpirationDate,
ct.id, ct.Name
FROM dbo.Employees e
LEFT JOIN dbo.Emails em ON em.EmployeeID = e.id
LEFT JOIN dbo.JobTitles jt ON e.JobTitleID = jt.id
LEFT JOIN Phones p ON p.EmployeeID = e.id
LEFT JOIN dbo.EmployeeCertificationType ect ON ect.EmployeeID = e.id
LEFT JOIN dbo.CertificationType ct ON ect.NameID = ct.id
WHERE e.id = #SelectedEmployeeID";
var employees = await connection.QueryAsync<EmployeeModel, EmailModel, TitleModel, PhoneModel, CertificationModel, EmployeeModel>(sql, (e, em, t, p, c) =>
{
e.EmailList.Add(em);
e.JobTitle = t;
e.PhoneList.Add(p);
e.CertificationList.Add(c);
return e;
},
par, splitOn: "EmployeeID, JobTitleID, EmployeeID, EmployeeID");
var result = employees.GroupBy(e => e.ID).Select(g =>
{
var groupedEmployee = g.First();
groupedEmployee.EmailList = g.Select(e => e.EmailList.Single()).ToList();
return groupedEmployee;
});
return result.ToList();
}
}
You only have one Employee. The other rows are because an Employee can have multiple Phones, Emails and Certifications.
I suggest you do something like this:
EmployeeModel employee = null;
await connection.QueryAsync<EmployeeModel, EmailModel, TitleModel, PhoneModel, CertificationModel, EmployeeModel>(sql, (e, em, t, p, c) =>
{
if (employee is null)
{
employee = e;
employee.JobTitle = t;
}
employee.EmailList.Add(em);
employee.PhoneList.Add(p);
employee.CertificationList.Add(c);
return employee;
},
par, splitOn: "EmployeeID, JobTitleID, EmployeeID, EmployeeID");
// go on using employee, no need for the employees list ...
Then you skip the afterburning of the list.
My suggestion is that you replace the call connection.QueryAsync<EmployeeModel> by other that returns only one element, as stated here

Dapper - QueryMultiple - 3 tables

I had this relation:
How to retrieve the information in an order entity and invoice entity with a QueryMultiple entity ?
Thanks
QueryMultiple is used when you are accessing multiple result sets, i.e. multiple select, as in:
select * from Order where Id=#id
select * from Invoice where Id = (...probably some sub-query)
At the moment, there is no inbuilt API to stitch this type of query together; instead you would do something like:
using(var multi = conn.QueryMultiple(...)) {
var order = multi.ReadSingle<Order>();
order.Invoice = multi.ReadSingleOrDefault<Invoice>(); // could be null if 0 rows
return order;
}
I would like to add an improved API for this scenario, but it is very awkward to express "join this to that using this property as the association, where {this}.{SomeMember} equals {that}.{SomeOtherMember}".
However, if you are actually doing a single query, as in:
select o.*, i.*
from Order o
left outer join Link l on ...
left outer join Invoice i on ...
where o.Id = #id
then you can use the various Query<,...,> overloads; for example:
int id = ...
var order = conn.Query<Order, Invoice, Order>(sql,
(x,y) => {x.Invoice = y; return x;}, args: new { id }, splitOn: "NumOrder").Single();
Generic code for three tables:
public static Tuple<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>> ExecuteQueryMultiple<T1, T2, T3>(string sql, object parameters,
Func<GridReader, IEnumerable<T1>> func1,
Func<GridReader, IEnumerable<T2>> func2,
Func<GridReader, IEnumerable<T3>> func3)
{
var objs = getMultiple(sql, parameters, func1, func2, func3);
return Tuple.Create(objs[0] as IEnumerable<T1>, objs[1] as IEnumerable<T2>, objs[2] as IEnumerable<T3>);
}
private static List<object> getMultiple(string procedureName, object param, params Func<GridReader, object>[] readerFuncs)
{
var returnResults = new List<object>();
using (SqlConnection sqlCon = new SqlConnection(connectionString))
{
var gridReader = sqlCon.QueryMultiple(procedureName, param, commandType: CommandType.StoredProcedure);
foreach (var readerFunc in readerFuncs)
{
var obj = readerFunc(gridReader);
returnResults.Add(obj);
}
}
return returnResults;
}
Controller:
[HttpPost]
public ActionResult GetCommodityDetails(int ID)
{
var data = new List<Commodity>();
DynamicParameters param = new DynamicParameters();
param.Add("#ATTRIBUTETYPE", "Your parameter");
param.Add("#CID", Your parameter);
var result = DapperORM.ExecuteQueryMultiple("Store procedure name", param, gr => gr.Read<order>(), gr => gr.Read<Invoice>(), gr => gr.Read<Link>());
return Json(result, JsonRequestBehavior.AllowGet);
}
You can use this concept. It worked for me

How to get value of column dynamically using Dapper

Using Dapper, how can I get the value of a column within a table dynamically?
What I have:
string tableName = "Table1";
int itemId = 1;
string columName = "MyBitColumn";
var query = string.Format("select {0} from {1} where {1}Id = #itemId", columnName, tableName);
var entity = conn.Query(query, new { itemId }).FirstOrDefault();
// I'd like something like this...
bool val = entity[columnName] as bool; // returns true or false, given that "MyBitColumn" is a bit in my sql db
Thanks!
You can cast the entity to an IDictionary<string, object> and access by name:
var entity = (IDictionary<string, object>) ... // your code
if((bool)entity[column name]) { ... }

How to return a Bool from a Where Filter using Entity Framework and Esql

I use c# and ef4.
I have a Model with an Entity with two proprieties int Id and string Title.
I need to write an ESQL query that is able to return bool TRUE if Id and Title are present in the DataSource. Please note Id is a PrimaryKey in my data storage.
Any idea how to do it?
You can do it by each code-snippets below:
1)
using (YourEntityContext context = new YourEntityContext ()) {
var queryString =
#"SELECT VALUE TOP(1) Model FROM YourEntityContext.Models
As Model WHERE Model.Id = #id AND Model.Title = #title";
ObjectQuery<Model> entityQuery = new ObjectQuery<Model>(queryString, context);
entityQuery.Parameters.Add(new ObjectParameter("id", id));
entityQuery.Parameters.Add(new ObjectParameter("title", title));
var result = entityQuery.Any();
}
2)
using (YourEntityContext context = new YourEntityContext ()) {
ObjectQuery<Model> entityQuery =
context.Models
.Where("it.Id = #id AND it.Title = #title"
, new ObjectParameter("id", id)
, new ObjectParameter("title", title)
);
var result = entityQuery.Any();
}
3)
var context = new YourEntityContext();
using (EntityConnection cn = context.Connection as EntityConnection) {
if (cn.State == System.Data.ConnectionState.Closed)
cn.Open();
using (EntityCommand cmd = new EntityCommand()) {
cmd.Connection = cn;
cmd.CommandText = #"EXISTS(
SELECT M FROM YourEntityContext.Models as M
WHERE M.Id == #id AND Model.Title = #title
)";
cmd.Parameters.AddWithValue("id", _yourId);
cmd.Parameters.AddWithValue("title", _yourTitle);
var r = (bool)cmd.ExecuteScalar();
}
}
4)
using (YourEntityContext context = new YourEntityContext ()) {
var queryString =
#"EXISTS(
SELECT M FROM YourEntityContext.Models as M
WHERE M.Id == #id AND Model.Title = #title
)";
ObjectQuery<bool> entityQuery = new ObjectQuery<bool>(queryString, context);
entityQuery.Parameters.Add(new ObjectParameter("id", id));
entityQuery.Parameters.Add(new ObjectParameter("title", title));
var result = entityQuery.Execute(MergeOption.AppendOnly).FirstOrDefault();
}
4 is the best way I suggest you. Good lock
What javad said is true, but another way is:
bool result = entities.Any(x=>x.Id == id && x.Title == title) ;
In fact because Id is primary key, DB prevent from occurrence of this more than one time .

Resources