Writing a Distinct LINQ query with a list - asp.net-mvc

I have the following LINQ query to fill up my model.
var blogs = (from b in Context.Blogs
select new BlogTreeView
{
Created = EntityFunctions.TruncateTime(b.Created),
Children = (from ba in Context.Blogs
where EntityFunctions.TruncateTime(ba.Created) == EntityFunctions.TruncateTime(b.Created)
select new BlogTitle
{
ID = ba.ID,
Title = ba.Title
})
}).Distinct();
The problem is that the distinct gives the following error:
"The 'Distinct' operation cannot be applied to the collection ResultType of the specified argument.\r\nParameter name: argument"
I also tried this:
var blogs = (from b in Context.Blogs
select new BlogTreeView
{
Created = EntityFunctions.TruncateTime(b.Created)
}).Distinct();
This gives me only the unique dates like I want.
Then I've tried to add the childrens to the model with the help of a foreach:
foreach (var item in blogs)
{
item.Children = (from ba in Context.Blogs
where
EntityFunctions.TruncateTime(ba.Created) ==
EntityFunctions.TruncateTime(item.Created)
select new BlogTitle
{
ID = ba.ID,
Title = ba.Title
});
}
But then my return value is null for the children list. In my foreach loop the Children list has the values that I want but not in the return field.
What am I doing wrong, and why did the first query gave me that error?

Related

MVC - Linq to SQL JOINS

I have a controller that accepts a list of strings. THese strings essentially are IDs that a user selects on the view. I need to build the model based upon fields from to tables, hence the need for the join. The bellow code will not build as it claims the properties from the joined table do not exist. It only accepts table 1 values. Item.Well_No and Item.Well_Name throw the error. These are included in the "y" table that i joined to "x"..
[HttpPost]
public ActionResult buildSelectionTable(List<string> dta)
{
var a = from x in db._AGREEMENTS
join y in db.WELL_AGMT_XREF on x.AGMT_NUM equals y.AGMT_NUM
where dta.Contains(x.AGMT_NUM)
select x;
List<AgmtModel> model = new List<AgmtModel>();
foreach (var item in a)
{
model.Add(new AgmtModel { Agmt_Name = item.AGMT_NAME, Agmt_Num = item.AGMT_NUM, Agmt_Type = item.AGMT_TYPE_DESCR, Amnt_Status = item.AGMT_STAT_DESCR, Company = item.CO_NAME, DaysToExp = item.DaysToExp, Drs_Url = item.DRS_URL, Effective_Date = item.EFF_DT, Orig_Lessee = item.ORIG_LESSEE, Prop_Status = item.AGMT_PROP_STAT_DESCR, Expiration_Date = item.EXPR_DATE, Acreage = item.LGL_AREA, Extention_Expiration = item.EXTN_EXPR_DT, WellNo = item.WELL_NO, Well_Name = item.WELL_NAME });
}
return PartialView("_SelectionTable", model);
}
You are only selecting x in your query you need to also select y and reference it.
change select x to be select new { x, y}
and then
foreach (var item in a)
{
model.Add(new AgmtModel { Agmt_Name = item.y.AGMT_NAME, Agmt_Num = item.x.AGMT_NUM ... });
}
you need to insert .x or .y before you the field to determine the field names
alternatively you could actually put the constructor directly in the query
so instead of select x
select new AgmtModel { Agmt_Name = y.AGMT_NAME, etc...}
then you can just return PartialView("_SelectionTable", a.ToList())

Failing to query from database

I'm trying to get a count of occurrences of a value from my database. It's failing.
My effort is
var dc = new Dal.Entities();
var query = (from d in dc.Instruments
where d.Src.ToLower().Contains("other.png")
select new
{
count = d.Src.Count(),
key = d.Src
}
);
This keeps throwing the following exception
"DbExpressionBinding requires an input expression with a collection ResultType.\r\nParameter name: input"
If I change select new... to select d then it works fine so I know that part of the query is OK.
I don't understand why I can't get a Count of each string it finds. What did I do wrong?
edit
If my database is
Src (column title)
my value
my other value
my value
I'm hoping to get the result of
my value, 2
my other value, 1
You need to group by then:
var query = from d in dc.Instruments
where d.Src.ToLower().Contains("other.png")
group d by d.Src into g
select new
{
count = g.Count(),
key = g.Key
};
var items = dc.Instruments
.Where(p => p.Src.ToLower().Contains("other.png"))
.Count();
or
var items = (from item in dc.Instruments
where item.Src.ToLower().Contains("other.png")
select item).Count();

How do I remove the foreach from this linq code?

I'm fairly new at MVC and linq and viewmodels in particular. I managed to get a create and index views to work. The "insert" wasn't as hard as the "list".
I have this linq query:
public ActionResult Index()
{
List<BlendElVM> BEVM = new List<BlendElVM>();
var list = (from Blend in db.blends
join BlendEl in db.blendEl on Blend.ID equals BlendEl.ID
select new
{
Blend.ID, Blend.Title, Blend.TransDt, BlendEl.Comment
}).ToList();
foreach (var item in list)
{
BlendElVM o = new BlendElVM(); // ViewModel
o.Comment = item.Comment;
o.Title = item.Title;
o.TransDt = item.TransDt;
o.ID = item.ID;
BEVM.Add(o);
}
return View(BEVM);
}
What I'm not sure about is the "foreach" section. When I'm running in debug, the "list" shows up fine, but if I comment out the "foreach" I get an error - ie not expecting the model. What does the foreach do? It has to do with the database, but I don't understand the where it is using the "o" and setting the columns. I thought it would all be in one linq query. Is it possible to combine the two and eliminate the "foreach"?
var BEVM = (from blend in db.blends
join BlendEl in db.blendEl on Blend.ID equals BlendEl.ID
select new BlendELVM
{
ID = blend.ID,
Title = blend.Title,
TransDT = blend.TransDt,
comment = blendEl.Comment
}).ToList();
I believe that the foreach is needed in order to read every element in the object so in this case you have:
BlendElVM o = new BlendElVM();
So you're creating and object named " o " of the type BlendELVM and this object contains all the attributes that you declared before which are: ID, Title, TransDT, etc
When you put:
foreach (var item in list)
{
BlendElVM o = new BlendElVM(); // ViewModel
o.Comment = item.Comment;
o.Title = item.Title;
o.TransDt = item.TransDt;
o.ID = item.ID;
BEVM.Add(o);
}
You're assigning to the new object o the item that you're reading in the list and in the end adding it to the BVEM list and answering if you can combine them i will say no because at first you're declaring the query and then you're reading the items on the list and assining them to the BEVM list

load navigation properties with filter for Entity Framework 4.3

Few days back I put a question regarding mapping two classes Message and MessageStatusHistory using EF. The mapping is going fine but I am facing some problems with the navigation property StatusHistory in class Message that relates it to MessageStatusHistory objects. I am loading the messages for one user only and want to the statuses pertaining to that user only. Like I would want to show if the user has marked message as read/not-read and when. If I use default loading mechanism like following it loads all the history related to the message irrespective of the user:
IDbSet<Message> dbs = _repo.DbSet;
dbs.Include("StatusHistory").Where(x=>x.MessageIdentifier == msgIdentifier);
To filter history for one user only I tried following trick:
IDbSet<Message> dbs = _repo.DbSet;
var q = from m in dbs.Include("StatusHistory")
where m.MessageIdentifier == msgIdentifier
select new Message
{
MessageIdentifier = m.MessageIdentifier,
/*OTHER PROPERTIES*/
StatusHistory = m.StatusHistory
.Where(x => x.UserId == userId).ToList()
};
return q.ToList();//THROWING ERROR ON THIS LINE
I am getting the error:
The entity or complex type 'MyLib.Biz.Message' cannot be constructed in a LINQ
to Entities query.
I have tried by commenting StatusHistory = m.StatusHistory.Where(x => x.UserId == userId).ToList() also but it has not helped.
Please help me in getting Messages with filtered StatusHistory.
EDIT:- above is resolved with this code:
var q = from m in _repository.DBSet.Include("Histories")
where m.MessageIdentifier == id
select new {
m.Id,/*OTHER PROPERTIES*/
Histories = m.Histories.Where(x =>
x.SenderId == userId).ToList()
};
var lst = q.ToList();
return lst.Select(m => new Message{
Id = m.Id, MessageIdentifier = m.MessageIdentifier,
MessageText = m.MessageText, Replies = m.Replies,
ReplyTo = m.ReplyTo, Histories = m.Histories, SenderId =
m.SenderId, SenderName = m.SenderName, CreatedOn = m.CreatedOn
}).ToList();
But if I try to include replies to the message with:
from m in _repository.DBSet.Include("Replies").Include("Histories")
I am getting error on converting query to List with q.ToList() for Histories = m.Histories.Where(x=> x.SenderId == userId).ToList().
About your EDIT part: You cannot use ToList() in a projection, just leave it an IEnumerable<T> and convert to a List<T> when you construct the Message. You also don't need to create two list objects, you can switch from the LINQ to Entities query to LINQ to Objects (the second Select) by using AsEnumerable():
var list = (from m in _repository.DBSet
where m.MessageIdentifier == id
select new {
// ...
Histories = m.Histories.Where(x => x.SenderId == userId)
})
.AsEnumerable() // database query is executed here
.Select(m => new Message {
// ...
Histories = m.Histories.ToList(),
// ...
}).ToList();
return list;
Be aware that Include has no effect when you use a projection with select. You need to make the properties that you want to include part of the projection - as you already did with select new { Histories.....

Issue With Showing Distinct fields using Linq

var getAllProducts = _productService.GetAllProducts();
if (productstest.Count > 0)
{
model.idproduct.Add(new SelectListItem()
{
Value = "0",
Text = _localizationService.GetResource("Common.All")
});
foreach (var m in getAllProducts)
model.idproduct.Add(new SelectListItem()
{
Value = m.Id.ToString(),
**Text = m.Size.Distinct().ToString(),**
Selected = model.Pid == m.Id
});
}
public virtual IList<Product> GetAllProducts(bool showHidden = false)
{
var query = from p in _productRepository.Table
orderby p.Name
where (showHidden || p.Published) &&
!p.Deleted
select p;
var products = query.ToList();
return products;
}
The issue is even i tried to populate the select list with distinct size using: Text = m.Size.Distinct().ToString(), but it shows the duplicate for instance 100 products are of size 33 cm , the list will populate the dropdownlist in the view with 33cm occuring 100 times , I dont want to show 100 times , just want to show 1 time, Can any one assist me with this issue ?
Presumably you are only trying to show one product of each different size... if so initialising your getAllProducts variable like so will do the trick:
var getAllProducts = _productService.GetAllProducts().GroupBy(p => p.Size).Select(g => g.First());

Resources