My problem is that when I have following 2 queries, 1st one is not populating the CampaignID property but 2nd one does. Here is my code;
query 1;
var query = from c in _context.MCTargets
where c.TargetDateFrom==d1 && c.TargetDateTo<=d2
group c by c.MarketingCampaignID into g
select new MSReport{
CampaignID = g.Key, // CampaignID is not populated here.
StartDate = d1,
EndDate = d2
};
query 2;
var query2 = from c in _context.MCTargets
where c.TargetDateFrom == d1 && c.TargetDateTo <= d2
group c by c.MarketingCampaignID into g
select new
{
CampaignID = g.Key,
StartDate = d1,
EndDate = d2
};
MSReport.cs
public class MSReport
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int CampaignID { get; set; }
public MSReport()
{
// CampaignID = 0 here
// doing something with CampaignID here like setting some calculated properties.
}
}
Thanks in advance and sorry for my poor explanation.
When using the object initializer syntax, the values specified in the initializer are set after the constructor for the object is executed. If you need the values that you are trying to populate to be available to the constructor, you must add a form of the constructor that takes the values as arguments and populates the fields or properties itself.
In your class:
public MSReport(int campaignID, DateTime startDate, DateTime endDate)
{
CampaignID = campaignID;
StartDate = startDate;
EndDate = endDate;
// doing something with CampaignID here like setting some calculated properties.
}
In your query:
new MSReport(g.Key, d1, d2)
This will work for Linq to SQL and Linq to Objects. For Linq to Entities a different approach must be taken.
You can execute the query with an anonymous object and then run a second query to transform it into your desired object:
var query = from c in _context.MCTargets
where c.TargetDateFrom==d1 && c.TargetDateTo<=d2
group c by c.MarketingCampaignID into g
select new {
CampaignID = g.Key,
StartDate = d1,
EndDate = d2
};
IEnumerable<MSReport> queryMSReports = from item in query.AsEnumerable()
select new MSReport(item.CampaignID, item.StartDate, item.EndDate);
This disconnects the object from Linq to Entities and allows you to create your desired objects with a constructor that has parameters. See the LINQ to Entites 'parameterless constructor' error forum post on MSDN for more information.
Your other option is to do the query using your MSReport class and the object initializer syntax then have a Calculate method on your class that you would have to call later.
Here is an example....
public class SimpleNameValueItem
{
public string Name { get; set; }
public Guid Uid { get; set; }
public int Id { get; set; }
public string Value { get; set; }
}
var shapeItems = from x in AppModel.ShapeTypes select new SimpleNameValueItem { Name = x.ShapeName, Uid = x.UID };
Where AppModel.ShapeTypes is entity of Entity Framework.
Maybe defalt constructor runs before initialization of params?
Try to add constructor in MSReport with your params and debug.
public class MSReport
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int CampaignID { get; set; }
public MSReport(int campaginId, ....)
{
// use and initialize camaginId here
}
}
and do:
select new MSReport(g.Key) {
StartDate = d1,
EndDate = d2
}
Related
I am currently loading two Orders and Colors tables, I wanted the Colors table to list the items that have the ID equal to Orders. For this, what occurred to me was to assign the IdOrders values to a variable and compare it with my IdOrders (in my table Colors), but it is not possible to assign the database's balance to my variable
My tables:
public partial class Orders
{
public int ID_Orders { get; set; }
public Nullable<System.DateTime> Data_Registo { get; set; }
public string Num_Encomenda { get; set; }
public string Ref_Cliente { get; set; }
}
public partial class Colors
{
public int ID_Orders { get; set; }
public int ID_Programa_Malha { get; set; }
public int ID_Linha_Cor { get; set; }
public string Cor { get; set; }
}
I am working with a database already in operation and possible these tables are already used in a sql join but not how to process that information.
As I said the first thing I remembered was to do this:
My Controller:
var id = from d in db.Orders
select d.ID_Orders;
var color = db.Colors.Where(x => x.ID_Orders = id).ToList();
var tables = new EncomendaViewModel
{
Orders= db.Orders.ToList(),
Colors= color.ToList(),
};
return View(tables);
Error in id: CS0029 C# Cannot implicitly convert type to 'int'
Is it possible to process the data in this way?
Thanks for anyone who can help!
-------------------(Update)------------------------------------------------
Using == cs0019 operator '==' cannot be applied to operands of type
My view in Broswer
dbEntities sd = new dbEntities();
List<Orders> orders= sd.Orders.ToList();
List<Colors> colers= sd.Colors.ToList();
var multipletable = from c in orders
join st in colers on c.ID_Programa equals st.ID_Programa into table1
from st in table1.DefaultIfEmpty()
select new MultipleClass { orders= c, colers= st };
There could be one or more values returned from the below query.
var id = from d in db.Orders
select d.ID_Orders;
That is the reason why it was throwing an error.
So lets try it this way
var color = db.Colors.Where(x => id.Contains(x.ID_Orders)).ToList();
public class OrderWithColorsViewModel
{
public Order order { get; set; }
public List<Colors> colers{ get; set; }
}
Public class TestOrderController : Controller
{
public DailyMVCDemoContext db = new DailyMVCDemoContext();
public ActionResult Index()
{
var orders= db.Orders.ToList();
var colers = db.Colors.ToList();
var result = (from c in orders
join st in colers on c.ID_Orders equals st.id into table1
select new OrderWithColorsViewModel { order =c, colers =
table1.ToList() }).ToList();
return View(result);
}
}
credits: YihuiSun
I have this error in my LINQ statement, however i dont understand whats the problem with it or how can i solve it:
This is my LINQ:
int year = 2016;
int month = 11;
DateTime dateFrom = new DateTime(year, month, 1);
DateTime dateTo = dateFrom.AddMonths(1);
int daysInMonth = DateTime.DaysInMonth(year, month);
var data = db_pdv.Pdv.Where(x => x.Fecha >= dateFrom && x.Fecha < dateTo);
var model_pdv = data.GroupBy(x => new { Pdv = x.Clave_PDV, Nombre_Pdv = x.Nombre_Pdv, Turno = x.Turno, Nombre_Turno = x.Nombre_Turno, Pla_ID = x.Platillo, Nombre_Platillo = x.Nombre_Platillo, Precio = x.Precio })
.Select(x => new DishVM()
{
Clave_PDV = x.Key.Pdv,
Nombre_Pdv = x.Key.Nombre_Pdv,
Turno = x.Key.Turno,
Nombre_Turno = x.Key.Nombre_Turno,
Platillo = x.Key.Pla_ID,
Nombre_Platillo = x.Key.Nombre_Platillo,
Precio = x.Key.Precio,
Days = new List<int>(new int[daysInMonth]),
Data = x
}).ToList();
And this is my "DishVM" CLass
public class DishVM
{
public string Clave_PDV { get; set; }
public string Nombre_Pdv { get; set; }
public string Turno { get; set; }
public string Nombre_Turno { get; set; }
public int Platillo { get; set; }
public string Nombre_Platillo { get; set; }
[DisplayFormat(DataFormatString = "{0:C}")]
public decimal Precio { get; set; }
public List<int> Days { get; set; }
[Display(Name = "Quantity")]
public int TotalQuantity { get; set; }
[DisplayFormat(DataFormatString = "{0:C}")]
[Display(Name = "Total")]
public decimal TotalPrice { get; set; }
public IEnumerable<Pdv> Data { get; set; }
}
How can i solve this problem?
Thanks in advance
How can I solve this problem?
Start by knowing what the problem is.
In Entity Framework, any expression that operates on a DbSet, like db_pdv.Pdv, is translated into SQL. The whole expression. In your case, this "whole expression" is model_pdv, which is structured as db_pdv.Pdv.Where(...).GroupBy(...).Select(). The expression contains new List<int>(new int[daysInMonth]). You'll understand that it's impossible to translate this into SQL; how would a database engine know how to construct a .Net List<T> object?
So how to solve it?
You could build the list first and then build the expression:
...
var daysList = new List<int>(new int[daysInMonth]);
var data = db_pdv.Pdv.Where(...
...
Precio = x.Key.Precio,
Days = daysList,
Data = x
Now you've reduced the SQL translation task to converting primitive values (integers) into SQL. EF knows perfectly well how to do that. But the result is... funny. If you check the generated SQL you see that EF converts the list of integers into some sort of a SQL table. Which looks like ...
CROSS JOIN (SELECT
0 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
0 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]
UNION ALL
SELECT
0 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable3]
UNION ALL
...
... etcetera.
What happens here, basically, is build a list in c#, convert it into a SQL construct, let the database construct a result set, convert the result set into a list in c# -- complicated.
Another option is to run the whole statement in memory:
var data = db_pdv.Pdv.Where(x => x.Fecha >= dateFrom && x.Fecha < dateTo)
.AsEnumerable();
var model_pdv = ...
Normally, I don't advocate this approach, for reasons explained here. But in this case it would be OK, because in the end you're going to use all data (Data = x), so you won't fetch more than you need from the database.
A more profound solution would be to remove the list from the view model altogether. Redundancy is the mother of inconsistency. Why should all model instances need the same list of integers? You should be able to build the list only once where you need it to present a UI.
I have classes like:
public class A {
public DateTime Date { get; set; }
public int Hour { get; set; }
public decimal Value { get; set; }
}
public class B {
public DateTime Date { get; set; }
public C C { get; set; }
}
public class C {
public int Hour { get; set; }
public decimal Value { get; set; }
}
I have a List<A> which contains a series of dates with hourly values for each. I'm trying to convert it from that format to that of type B, so a List<B>.
For instance, if there were 3 days' worth of data in the List<A> (i.e. 24 x 3 = 72 records), then there should be 3 objects of type B in the List<B> - one for each day with the 24 hours split up into the C type.
I know I can do it with nested foreach loops but I figured LINQ would be more elegant and would likely be better performance wise as well.
The code I'm trying is:
var res = from a in AList
select (new List<B>
{
new B
{
Date = a.Date,
C = new C()
{
Hour = a.Hour,
Value = a.Value
}
}
});
But it returns a list without the date grouping. I'm not sure how to establish that grouping. Would appreciate any help!
Logically, it seems like your B class should contain a collection of C instances:
public class B {
public DateTime Date { get; set; }
public ICollection<C> C { get; set; }
}
Consequently, you could use group by to populate these instances:
var res =
(
from a in AList
group a by a.Date into g
select new B
{
Date = g.Key,
C =
(
from c in g
select new C
{
Hour = c.Hour,
Value = c.Value
}
).ToList()
}
).ToList();
var newAList = from a in AList
select new B
{
Date = a.Date,
C = new C { Hour = a.Hour, Value = a.Value }
};
LINQ: Elegant? Yes. But better performance than nested loops? I'm not sure about it.
I am having date details which is in format (dd/mm/yyyy) like,
Table #1
id Name date User
--------------------------------
1 xxx 01/01/2016 user1
2 yyy 01/02/2016 user2
3 aaa 02/03/2016 user1
Table #2
id Name date
--------------------
1 xxx 07/01/2016
2 xxx 09/01/2016
3 yyy 05/02/2016
4. aaa 04/03/2016
EDIT 1:
The logic is, For the First time the xxx occured in Table2 means, it gets the date from the Table1 to compute the day difference. For the next time xxx value occured means, it get thes the date from Table2 (not table1) Because the Table2 already have the value in that table.So the day difference will compute by using Table2 alone. Same for the other values too.
EDIT 2:
Actually, I need to get the date difference for the value. I have to get the date difference by using Table1 if the Name is occurred First time. And to get the Dtae difference from Table2 , If the Name is occurred before.
I am having 'Name' field as UNIQUE
Result should be like,
user Name DateDifference
------------------------------------
user1 xxx 6 (07/01/2016 - 01/01/2016)
user1 xxx 2 (07/01/2016 - 09/01/2016)
user2 yyy 4 (01/02/2016 - 05/02/2016)
user1 aaa 2 (02/03/2016 - 04/03/2016)
LINQ query I have tried is,
var query = (from item1 in Table1
join item2 in Table1 on item1.Name equals item2.Name
where item2.Date > item1.Date
join origin in Table2 on item1.Name equals origin.Name
where // condition
group new { item1,item2 } by new { item1.Name,item1.Date } into grp
select new
{
DayDiff = DbFunctions.DiffDays(grp.Key.Date, grp.Min(d => d.item2.Date)),
}
).ToList();
But I could not get the result expected. I am also aware of this question, How to get the date difference by joining two tables? , But finally they did not end it in proper LINQ query option.
How my question differ from How to get the date difference by joining two tables? ?
The answer is in SQL. I need to code it in LINQ.
I hope at least you have navigation property over those two tables.Try this
class Program
{
static void Main(string[] args)
{
using (var db = new aaContext2())
{
IList<DTO> dto = new List<DTO>();
dto = db.Table2.Select(a => new DTO
{
Name = a.Name,
User = a.Namea.User,
DateDifference = (DbFunctions.DiffDays(a.Date, db.Table2.Where(aa => aa.Name.Equals(a.Name) && a.Date < aa.Date).Min(dd => dd.Date)
) ?? (DbFunctions.DiffDays(db.Table1.Where(aa => aa.Name.Equals(a.Name)).Min(aaa => aaa.Date), a.Date)))
}).ToList();
}
}
}
public class DTO
{
public string User { get; set; }
public string Name { get; set; }
public int? DateDifference { get; set; }
}
public class aaContext2 : DbContext
{
public DbSet<Table1> Table1 { get; set; }
public DbSet<Table2> Table2 { get; set; }
}
public class Table1
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<Table2> NameList { get; set; }
public DateTime Date { get; set; }
public string User { get; set; }
}
public class Table2
{
public int Id { get; set; }
public virtual Table1 Namea { get; set; }
public string Name { get; set; }
public DateTime Date { get; set; }
}
}
Here is one possible way:
var query =
(from t1 in db.Table1
join t2 in db.Table2 on t1.Name equals t2.Name
let prevDate = (from t3 in db.Table2
where t3.Name == t2.Name && t3.Date < t2.Date
select (DateTime?)t3.Date).Max() ?? t1.Date
select new
{
t1.User,
t1.Name,
DayDiff = DbFunctions.DiffDays(prevDate, t2.Date).Value,
}).ToList();
I wanted the date diff to be inside where condition not outside the query so this form helped me:
Found it on forums.asp.net
Here's a sample showing one way to get all employees with a DOB between now and 14 days from now...
var employeesWithBirthday =
from emp in dc.Employees
let BirthdayDiff = (new DateTime(DateTime.Now.Year, emp.BirthDate.Month, emp.BirthDate.Day) - DateTime.Now).TotalDays
where BirthdayDiff >= 0 && BirthdayDiff <= 14
select emp;
...although, be aware that a query like that will do a table scan (can't use any indexes)...
So i want to achieve something like:
var query = from p in db.Project
select new A
{
Project = p,
Capacity = new List<Capacity>((from pp in db.ProjectActualCapacity
where pp.ProjectID == p.ID
select new Capacity
{
Actual = pp.Hours,
Date = pp.Date,
ProjectID = pp.ProjectID
}
).ToList())
};
However, when the query is converted to list. It throws the following error
Only parameterless constructors and initializers are supported in LINQ to Entities.
Is there a workaround to this?
thanks
//Update
public class Capacity
{
public DateTime Date { get; set; }
public decimal? Actual { get; set; }
public decimal? Projected { get; set; }
public int ProjectID { get; set; }
public decimal Rate { get; set; }
}
You are explicitly creating a list and using the constructor which accepts an enumerable. This is not necessary since you are already using .ToList() where you define that collection.
Also, your Capacity class needs a parameterless constructor.
So I think it will work like this.
var query = from p in db.Project
select new A {
Project = p,
Capacity = (from pp in db.ProjectActualCapacity
where pp.ProjectID == p.ID
select new Capacity {
Actual = pp.Hours,
Date = pp.Date,
ProjectID = pp.ProjectID
}
).ToList())
};