MVC Razor Var data - linq

Hi i am new to MVC3 Razor .
I was trying to display the values from the database table.
in controller i wrote the code as
var test1 = from ed in db.EmpDetails
join dp in db.Departments on ed.EmpDept equals dp.DeptId
select new
{
EmpId = ed.EmpId,
EmpName = ed.EmpName,
EmpDesignation = ed.EmpDesignation,
EmpSalary = ed.EmpSalary,
EmpUserName =ed.EmpUserName,
EmpDept =ed.EmpDept,
deptName = dp.deptName
};
ViewBag.test = test1;
and in the view
#foreach (var tm in ViewBag.test)
{
string abc =#tm.EmpName;
// and the logic
}
Here i am getting all the value in the "tm" variable. But when i try to get the particular value of EmpName in a string it is showing the error as "'object' does not contain a definition for 'EmpName'".
Please help me to solve this error.
Thanks
san

Unfortunately anonymous objects doesn't work with Views. Either you need to return a non-anonymous to view Or return a dynamic object to view.
Refer : http://rhizohm.net/irhetoric/post/2011/05/25/Taking-The-M-out-of-MVC-JSON-The-dynamic-Keyword-LINQ-.aspx

You cannot use anonymous objects in views. Try like this:
var test1 =
from ed in db.EmpDetails
join dp in db.Departments on ed.EmpDept equals dp.DeptId
select ed;
ViewBag.test = test1;
and then:
#foreach (var tm in (IEnumerable<Employee>)ViewBag.test)
{
string abc = tm.EmpName;
// and the logic
}
But personally I would recommend you using strongly typed views instead of ViewBag:
var test1 =
from ed in db.EmpDetails
join dp in db.Departments on ed.EmpDept equals dp.DeptId
select ed;
return View(test1);
and inside the view:
#model IEnumerable<Employee>
#foreach (var tm in Model)
{
string abc = tm.EmpName;
// and the logic
}

I am able to get the values in the view if i convert linq result to toList() in controller.
Like
var test = (from p in db.EmpDetails orderby p.EmpName ascending select p).ToList();
ViewBag.test = test;
And in the view
#foreach (var tm in ViewBag.test)
{
int emId = #tm.id;
}
Thanks....

Related

Subtract dates in Linq EF6

Hello i have big problem with Subtract at Linq,EF6.
I have date where repair should be finieshed. I woluld like to count how many days left.
At ViewModel I have:
public TimeSpan TimeToLeft{get;set;}
At repair controler i do sth like this:
var repairsToDo = from r in db.Repairs
join c in db.Car on r.Car equals c.ID_Car
join m in db.Models on c.ID_Modelu equals m.ID_Modelu
join b in db.Brand on m.ID_Brand equals b.Brand
where r.Data_Zakonczenia>=DateTime.Today
select new RepairsToDo { TimeToLeft=(r.EndDate-DateTime.Today) };
View:
<table class="ShowDataTab">
<tr>
<th>Repair Number</th>
<th>Car</th>
<th>Name</th>
<th>Desc</th>
<th>Time to left</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>#item.FixNumber</td>
<td>#item.Brand#item.Model</td>
<td>#item.FixName</td>
<td>#item.FixDesc</td>
<td>#item.TimeToLeft</td>
</tr>
}
</table>
And i got error like this:
dbarithmeticexpression arguments must have a numeric common type
How can i Fix it?
EDIT1:
Controler:
var today = DateTime.Today;
var repairsToDo = from r in db.Repair
join c in db.Car on r.Car equals c.ID_Car
join m in db.Models on c.ID_Model equals m.ID_Model
join b in db.Brand on m.ID_Brand equals b.ID_Brand
where r.EndTime>=DateTime.Today
select new { ... EndTime=r.EndTime };
var model = repairsToDo.AsEnumerable().Select(raw => new RepairsToDo {... TimeLeft= raw.EndTime- today });
return View(model);
Error:
The model item passed into the dictionary is of type 'System.Linq.Enumerable+WhereSelectEnumerableIterator`2[<>f__AnonymousType1a`7[System.Int32,System.String,System.String,System.String,System.String,System.String,System.DateTime],Praca_Inzynierska.Models.RepairsToDo]', but this dictionary requires a model item of type 'System.Linq.IQueryable`1[Praca_Inzynierska.Models.RepairsToDo]'.
enter code here
It's probably simplest to just fetch the data from EF, and then perform the arithmetic locally:
var today = DateTime.Today;
var rawData = from r in db.Repairs
join c in db.Car on r.Car equals c.ID_Car
join m in db.Models on c.ID_Modelu equals m.ID_Modelu
join b in db.Brand on m.ID_Brand equals b.Brand
where r.Data_Zakonczenia >= DateTime.Today
select new { ..., r.EndDate };
var model = rawData.AsEnumerable() // Perform the select locally
.Select(raw => new RepairsToDo {
... // other properties
TimeToLeft = raw.EndDate - today
});
Note that I've fetched DateTime.Today once, rather than doing it multiple times - that way you'll get a consistent result, even if this query is performed around midnight.
I'd also recommend renaming TimeToLeft as TimeLeft or RemainingTime.
Try:
TimeToLeft = SqlFunctions.DateDiff("DAY", r.EndDate, DateTime.Now)
Change DAY for whatever unit you want. See http://msdn.microsoft.com/en-us/library/dd487052(v=vs.110).aspx and http://msdn.microsoft.com/en-us/library/ms189794.aspx.
With EF6 use
System.Data.Entity.DbFunctions.DiffHours(time1,time2).Value
for example:
using System.Data.Entity;
...
entity.tableData.Select(m => new
{
m.Key,
horasTotales = m.Sum(h => DbFunctions.DiffHours(h.fecha_fin, h.fecha_inicio).Value)
})

Explicit construction of entity type in query is not allowed [duplicate]

Using Linq commands and Linq To SQL datacontext, Im trying to instance an Entity called "Produccion" from my datacontext in this way:
Demo.View.Data.PRODUCCION pocoProduccion =
(
from m in db.MEDICOXPROMOTORs
join a in db.ATENCIONs on m.cmp equals a.cmp
join e in db.EXAMENXATENCIONs on a.numeroatencion equals e.numeroatencion
join c in db.CITAs on e.numerocita equals c.numerocita
where e.codigo == codigoExamenxAtencion
select new Demo.View.Data.PRODUCCION
{
cmp = a.cmp,
bonificacion = comi,
valorventa = precioEstudio,
codigoestudio = lblCodigoEstudio.Content.ToString(),
codigopaciente = Convert.ToInt32(lblCodigoPaciente.Content.ToString()),
codigoproduccion = Convert.ToInt32(lblNroInforme.Content.ToString()),
codigopromotor = m.codigopromotor,
fecha = Convert.ToDateTime(DateTime.Today.ToShortDateString()),
numeroinforme = Convert.ToInt32(lblNroInforme.Content.ToString()),
revisado = false,
codigozona = (c.codigozona.Value == null ? Convert.ToInt32(c.codigozona) : 0),
codigoclinica = Convert.ToInt32(c.codigoclinica),
codigoclase = e.codigoclase,
}
).FirstOrDefault();
While executing the above code, I'm getting the following error that the stack trace is included:
System.NotSupportedException was caught
Message="The explicit construction of the entity type 'Demo.View.Data.PRODUCCION' in a query is not allowed."
Source="System.Data.Linq"
StackTrace:
en System.Data.Linq.SqlClient.QueryConverter.VisitMemberInit(MemberInitExpression init)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitSelect(Expression sequence, LambdaExpression selector)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.Visit(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.VisitFirst(Expression sequence, LambdaExpression lambda, Boolean isFirst)
en System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
en System.Data.Linq.SqlClient.QueryConverter.VisitInner(Expression node)
en System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(Expression node)
en System.Data.Linq.SqlClient.SqlProvider.BuildQuery(Expression query, SqlNodeAnnotations annotations)
en System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query)
en System.Data.Linq.DataQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression)
en System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
en Demo.View.InformeMedico.realizarProduccionInforme(Int32 codigoExamenxAtencion, Double precioEstudio, Int32 comi) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 602
en Demo.View.InformeMedico.UpdateEstadoEstudio(Int32 codigo, Char state) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 591
en Demo.View.InformeMedico.btnGuardar_Click(Object sender, RoutedEventArgs e) en D:\cs_InformeMedico\app\InformeMedico.xaml.cs:línea 683
InnerException:
Is that now allowed in LINQ2SQL?
Entities can be created outside of queries and inserted into the data store using a DataContext. You can then retrieve them using queries. However, you can't create entities as part of a query.
I am finding this limitation to be very annoying, and going against the common trend of not using SELECT * in queries.
Still with c# anonymous types there is a workaround, by fetching the objects into an anonymous type, and then copy it over into the correct type.
For example:
var q = from emp in employees where emp.ID !=0
select new {Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.ToList();
List<User> users = new List<User>(r.Select(new User
{
Name = r.Name,
EmployeeId = r.EmployeeId
}));
And in the case when we deal with a single value (as in the situation described in the question) it is even easier, and we just need to copy directly the values:
var q = from emp in employees where emp.ID !=0
select new { Name = emp.First + " " + emp.Last, EmployeeId = emp.ID }
var r = q.FirstOrDefault();
User user = new User { Name = r.Name, EmployeeId = r.ID };
If the name of the properties match the database columns we can do it even simpler in the query, by doing select
var q = from emp in employees where emp.ID !=0
select new { emp.First, emp.Last, emp.ID }
One might go ahead and write a lambda expression that can copy automatically based on the property name, without needing to specify the values explictly.
Here's another workaround:
Make a class that derives from your LINQ to SQL class. I'm assuming that the L2S class that you want to return is Order:
internal class OrderView : Order { }
Now write the query this way:
var query = from o in db.Order
select new OrderView // instead of Order
{
OrderID = o.OrderID,
OrderDate = o.OrderDate,
// etc.
};
Cast the result back into Order, like this:
return query.Cast<Order>().ToList(); // or .FirstOrDefault()
(or use something more sensible, like BLToolkit / LINQ to DB)
Note: I haven't tested to see if tracking works or not; it works to retrieve data, which is what I needed.
I have found that if you do a .ToList() on the query before trying to contruct new objects it works
I just ran into the same issue.
I found a very easy solution.
var a = att as Attachment;
Func<Culture, AttachmentCulture> make =
c => new AttachmentCulture { Culture = c };
var culs = from c in dc.Cultures
let ac = c.AttachmentCultures.SingleOrDefault(
x => x.Attachment == a)
select ac == null ? make(c) : ac;
return culs;
I construct an anonymous type, use IEnumerable (which preserves deferred execution), and then re-consruct the datacontext object. Both Employee and Manager are datacontext objects:
var q = dc.Employees.Where(p => p.IsManager == 1)
.Select(p => new { Id = p.Id, Name = p.Name })
.AsEnumerable()
.Select(item => new Manager() { Id = item.Id, Name = item.Name });
Within the book "70-515 Web Applications Development with Microsoft .NET Framework 4 - Self paced training kit", page 638 has the following example to output results to a strongly typed object:
IEnumerable<User> users = from emp in employees where emp.ID !=0
select new User
{
Name = emp.First + " " + emp.Last,
EmployeeId = emp.ID
}
Mark Pecks advice appears to contradict this book - however, for me this example still displays the above error as well, leaving me somewhat confused. Is this linked to version differences? Any suggestions welcome.
I found another workaround for the problem that even lets you retain your result as IQueryale, so it doesn't actually execute the query until you want it to be executed (like it would with the ToList() method).
So linq doesn't allow you to create an entity as a part of query? You can shift that task to the database itself and create a function that will grab the data you want. After you import the function to your data context, you just need to set the result type to the one you want.
I found out about this when I had to write a piece of code that would produce a IQueryable<T> in which the items don't actually exist in the table containing T.
pbz posted a work around by creating a View class inherited from an entity class that you could be working with. I'm working with a dbml model of a table that has > 200 columns. When I try and return the whole table I get "Root Element missing" errors. I couldn't find anyone who wanted to deal with my particular issue so I was looking at rewriting my entire approach. Just creating a view class for the entitiy class worked in my case.
As pbz suggests : Create a view class that inherits from your entity class. For me this is tbCamp so :
internal class tbCampView : tbCamp
{
}
Then use the view class in your query :
using (var dc = ConnectionClass.Connect(Dev))
{
var camps = dc.tbCamps.Select(s => new tbCampView
{
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
SmartTableViewer(camps, dg1);
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
Here is what happens when you try and create an entity class object in the query.
I didn't want to have to use an anonymous type if I could help it because I wanted the type to be tbCamp. Since tbCampView is of type tbCamp the is operator works well. see Brian Hasden's answer Passing a generic List<> in C#
I'm surprised this is even an issue but with larger tables I run into this error so I thought I would just show it here :
When trying to read this table into memory I get the following error. There are < 2000 rows but the columns are > 200 for each. I don't know if that is an issue or not.
If I just want a few columns I need to create a custom class and handle that which isn't that big of a pain. With the approach pbz provided I don't have to worry about it.
Here is the entire project in case it helps someone.
public partial class Form1 : Form
{
private const bool Dev = true;
public Form1()
{
InitializeComponent();
}
private void btnGetAllCamps_Click(object sender, EventArgs e)
{
using (var dc = ConnectionClass.Connect(Dev))
{
IQueryable<tbCampView> camps = dc.tbCamps.Select(s => new tbCampView
{
// Project columns as needed.
active = s.active,
idCamp = s.idCamp,
campName = s.campName
});
// pass in as a
SmartTableViewer(camps);
}
}
private void SmartTableViewer<T>(IEnumerable<T> allRecords)
{
// Build sorted rows back into new table
var table = new DataTable();
// Create columns based on type
if (allRecords is IEnumerable<tbCamp> tbCampRecords)
{
// Get the columns you want
table.Columns.Add("idCamp");
table.Columns.Add("campName");
foreach (var record in tbCampRecords)
{
//var newRecord = record;
// Make a new row
var r = table.NewRow();
// Add the contents to each column of the row
r["idCamp"] = record.idCamp;
r["campName"] = record.campName;
// Add the row to the table.
table.Rows.Add(r);
}
}
else
{
MessageBox.Show("Unhandled type. Add support for new data type in SmartTableViewer()");
return;
}
// Update table in grid
dg1.DataSource = table.DefaultView;
}
internal class tbCampView : tbCamp
{
}
}

showing multiple rows from database in datagridview using entity framework

I am trying to show multiple records from database in datagridview but I'm having only a single record all the time.
2 tables are involved in this query, from 1st table I acquire all the id's those fulfill the condition and from 2nd table I am getting the user information.
1st table is tblUsers_Roles and 2nd is tblUsers.
These tables have primary/foriegn key relationship.
Here is my code:
IEnumerable<tblUsers_Role> id = db.tblUsers_Role.Where(a => a.User_Role == selectRole);
foreach (var user in id)
{
var userinfo = from b in db.tblUsers
where b.User_Id == user.User_Id
select new { b.First_Name, b.Last_Name, b.Status, b.Authenticated };
dgvResults.DataSource = userinfo.ToList();
dgvResults.Show();
}
You are assigning the grid in the loop. That is not going to work. Maybe something like this will work:
var userinfo =(from ur in db.tblUsers_Role
join u in db.tblUsers
on ur.User_Id equals u.User_Id
where ur.User_Role == selectRole
select new
{
u.First_Name,
u.Last_Name,
u.Status,
u.Authenticated
}).ToList();
dgvResults.DataSource = userinfo;
dgvResults.Show();
Or a alteretive would be like this:
var roles=db.tblUsers_Role
.Where(a => a.User_Role == selectRole)
.Select (a =>a.User_Id).ToList();
var userinfo=
(
from u in db.tblUsers
where roles.Contains(u.User_Id)
select new
{
u.First_Name,
u.Last_Name,
u.Status,
u.Authenticated
}
).ToList();
dgvResults.DataSource = userinfo;
dgvResults.Show();
Not as nice as the first one. But maybe you understand the concept.

How can I call a Linq-to-Entities (EF4) query specifying a different table name dynamically?

I have a bunch of tables that all have a field called ResourceID that are populated from an outside process. I want to go through each table and validate that ID against a master list. The code is simple but gets repetitive:
var resList = (from r in dc.ResourceMasterEntities select r.ResourceId).ToList();
var res = (from rs in resList select (int?)rs).ToList();
var stage = (from s in dc.TableOne select s.ResourceId).ToList();
foreach (var invalidResourceID in stage.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID );
}
stage = (from s in dc.TableTwo select s.ResourceId).ToList();
foreach (var invalidResourceID in stage.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID );
}
// more of the same with different tables
I would like to create a function where I can pass in the name of the table (TableOne, TableTwo, etc) and not have to write all of this repetitive code. Can this be done with Linq? (and preferably not using ExecuteQuery :-))
You can create a function that takes an IQueryable as a parameter.
The function would look like:
private void CheckTable(IQueryable<EntityType> table)
{
var stage = (from s in table select s.ResourceId).ToList();
foreach (var invalidResourceID in stage.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID);
}
}
// Execute the function like:
CheckTable(dc.TableOne);
You can choose if you make errList and res class level properties or if you pas them as parameters to the function
With some modification I was able to get this to work - I had to use the built in dynamic linq to select the property that I wanted.
private void CheckTable(System.Data.Objects.ObjectSet<EntityType> table)
{
var records = table.Select("BusinessEntityNbr").ToList();
var values = (from r in records select (int?)r[0]).ToList();
foreach (var invalidResourceID in values.Except(res).ToList())
{
errList.Add("Bad ID found:" + invalidResourceID);
}
}
You may want to consider using entity SQL and DbDataRecord for unknown result types. See the Entity SQL samples in http://archive.msdn.microsoft.com/EFQuerySamples for some ideas on how to use Entity SQL.

Error: "The xml data type cannot be selected as DISTINCT because it is not comparable."

In my code I have the following Linq Query:
IQueryable<Data> charts = (from report in ctx.Charts group report by new
{
Name = report.ChartTitle.ChartType.ChartCategory.CategoryName,
id = report.ChartTitle.ChartType.ChartCategory.ChartCategoryId,
Period = report.Period
} into d
select new Data
{
Name = d.Key.Name,
Id = d.Key.id,
Period = d.Key.Period,
Reports = from r in d group r by new
{ Title = r.ChartTitle.Name, id = r.ChartTitle.ChartTitleId } into rs
select new Report
{
Title = rs.Key.Title,
Id = rs.Key.id,
Charts = (from c in rs group c by new
{
ChartId = c.ChartId,
FiscalYear = c.FiscalYear,
ModifiedDate = c.ChartView.ModifiedDate,
Function = c.Function.DisplayName,
ChartData=c.ChartView.ViewData
} into cs
select new ChartInfo
{
ChartId = cs.Key.ChartId,
FiscalYear = cs.Key.FiscalYear,
ModifiedDate = cs.Key.ModifiedDate,
Function = cs.Key.Function,
ChartData=cs.Key.ChartData
})
}});
In the above code if I exclude the "ChartData" field (which is of XML datatype), the query executes fine. But when ever I include this field it throws the following error :"The xml data type cannot be selected as DISTINCT because it is not comparable."
Let me know what I am missing here?
You can't group by XML types. This is a SQL restriction, not a LINQ-to-SQL retriction. (See Group by on XML column field with LINQ and select an xml type column in select query with group by SQL Server 2008)
Do you need to group by the XML column? The alternative would be to group by your other columns and then select the first XML value as a result.
Charts = (from c in rs group c by new
{
ChartId = c.ChartId,
FiscalYear = c.FiscalYear,
ModifiedDate = c.ChartView.ModifiedDate,
Function = c.Function.DisplayName,
} into cs
select new ChartInfo
{
ChartId = cs.Key.ChartId,
FiscalYear = cs.Key.FiscalYear,
ModifiedDate = cs.Key.ModifiedDate,
Function = cs.Key.Function,
ChartData=cs.Value.FirstOrDefault().ChartData
})
When using LINQ-to-SQL the items being grouped are still accessible - you don't need to include every 'selected' property / column in the group by` clause like you would in SQL.
You did not tell us what is the actual datatype of the ChartData, but from the error you are describing it looks like the problem is that whatever this datatype is it does not implement the IComparable interface which is a required interface if you want instances of the datatype to be comparable

Resources