How to include FirstOrDefault() in ToList() - asp.net-mvc

I want to get only one file for each recipe.
var UploadedFiles = (from rec in db.Recipes
join files in db.Files on rec.Id equals files.RecipeId
select new
{
files.Id,
files.Path,
files.RecipeId,
rec.Name,
rec.Description,
rec.Category,
rec.CookTime
}).ToList();
return new JsonResult { Data = UploadedFiles, JsonRequestBehavior = JsonRequestBehavior.AllowGet };

You could use group join instead of regular join, I presume it is also more efficient than the previous answer (with the let), although I am not fully aware of EF query optimizations in this case
var UploadedFiles = (from rec in db.Recipes
join files in db.Files on rec.Id equals files.RecipeId into g
let firstFile = g.FirstOrDefault()
select new
{
firstFile.Id,
firstFile.Path,
firstFile.RecipeId,
rec.Name,
rec.Description,
rec.Category,
rec.CookTime
}).ToList();
Update
since I don't use EF, I can't really confirm whether or not it handles nulls but I have been informed it doesn't you would have to remove nulls.
var UploadedFiles = (from rec in db.Recipes
join files in db.Files on rec.Id equals files.RecipeId into g
let firstFile = g.FirstOrDefault()
where firstFile != null
select new
{
firstFile.Id,
firstFile.Path,
firstFile.RecipeId,
rec.Name,
rec.Description,
rec.Category,
rec.CookTime
}).ToList();

You can try the following...
var UploadedFiles = (from rec in db.Recipes
from files in db.Files.FirstOrDefault(f => f.RecipeId == rec.Id)
select new
{
files.Id,
files.Path,
files.RecipeId,
rec.Name,
rec.Description,
rec.Category,
rec.CookTime
}).ToList();
return new JsonResult { Data = UploadedFiles, JsonRequestBehavior =
JsonRequestBehavior.AllowGet };

Related

Retrieve data in asp.net MVC from complex stored procedure which return multiple actual table

User Defined Stored Procedure which returns multiple actual table as result set.
CREATE PROCEDURE uspDemo(
#UserID BIGINT=0,
#IsAdmin bit=0,
#Title varchar(120)=''
)AS
BEGIN
------Retrieve Posts------
SELECT * FROM tblPost AS MP INNER JOIN tblUserProfile AS UP ON UP.ID=MP.UserID
WHERE UP.ID=#UserID AND ((#IsAdmin=0 AND MP.IsDeleted=0 AND MP.IsApproved=1)OR (#IsAdmin=1 OR MP.IsDeleted=0 OR MP.IsApproved=1))
----- Retrieve Tags------
SELECT * FROM tblTagMasters AS MT INNER JOIN tblPostTags AS MP ON MT.TagID= MP.TagID
--------Retrieve User likes-----
SELECT * FROM tblUserLikes AS UV INNER JOIN tblPost AS MP ON MP.PostId=UV.PostId
END
I want to convert into list format of all returned actual table from stored procedure according to model in asp.net MVC.
public List<PostView> GetPosts(int userID = 0, string s = "")
{
IEnumerable<PostView> query = null;
using (var db = new MVCDatabase())
{
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[uspDemo]";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#UserID", userID));
cmd.Parameters.Add(new SqlParameter("#IsAdmin", 0));
cmd.Parameters.Add(new SqlParameter("#Title", s));
try
{
db.Database.Connection.Open();
using (var result = cmd.ExecuteReader())
{
var Posts = ((IObjectContextAdapter)db).ObjectContext.Translate<PostView>(result).ToList();
result.NextResult();
var tags = ((IObjectContextAdapter)db).ObjectContext.Translate<TagView>(result).ToList();
result.NextResult();
var uservotes = ((IObjectContextAdapter)db).ObjectContext.Translate<UserVoteView>(result).ToList();
Posts.ForEach(z =>
{
z.TagMaster = tags.Where(x => x.PostId == z.PostId).ToList();
z.UserLike = uservotes.Where(x => x.PostId == z.PostId).ToList();
});
query = Posts;
}
}
catch (Exception ex)
{
MSError.Trace(ex);
}
finally
{
db.Database.Connection.Close();
cmd.Dispose();
}
return query.ToList();
}
}
Throwing an ArgumentNullException
Help me to find out the solution.
Here is a demo how to do it. Using System.data and System.Linq you can do below.
var cmd = db.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[uspDemo]";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#UserID", userID));
cmd.Parameters.Add(new SqlParameter("#IsAdmin", 0));
cmd.Parameters.Add(new SqlParameter("#Title", s));
SqlDataAdapter da = new SqlDataAdapter(); //adapter
DataSet ds = new DataSet(); //dataset
cmd.CommandType = CommandType.StoredProcedure;
da = new SqlDataAdapter(cmd);
da.Fill(ds); //fill dataset with multiple select
var Posts = (from DataRow row in ds.Tables[0].Rows //0 means 1st select
select new Posts //Posts model to map
{
test = row["test"].ToString(), //test is the column name from select
test1 = Convert.ToDecimal(row["test1"])
}).ToList();
var Tags = (from DataRow row in ds.Tables[1].Rows //1 means 2nd select
select new Tags //Tags model to map
{
test = row["test"].ToString(), //test is the column name from select
test1 = Convert.ToDecimal(row["test1"])
}).ToList();
var User = (from DataRow row in ds.Tables[2].Rows //2 means 3rd select
select new User //User model to map
{
test = row["test"].ToString(), //test is the column name from select
test1 = Convert.ToDecimal(row["test1"])
}).ToList();

Entity Framework (v6) Eager-Loading weird behaviour - 'Gotcha'

Should the following two queries be equivalent?
(note the placement of .Include)
== (V1)
using (var ctx = new Entities()) {
ctx.Configuration.ProxyCreationEnabled = false; //return stronglyTyped Entity, not dynamic entity...
IQueryable<TB_MyHeader> query = from hd in ctx.TB_MyHeader.Include(h => h.TB_MyLines)
join wo in ctx.TB_AnotherTable on hd.fkId equals wo.ID
where wo.woPk == #id
orderby hd.PoItem
select hd;
var headerPlusLines = query
.AsNoTracking()
.ToList();
return headerPlusLines;
}
== (V2)
using (var ctx = new Entities()) {
ctx.Configuration.ProxyCreationEnabled = false; //return stronglyTyped Entity, not dynamic entity...
IQueryable<TB_MyHeader> query = (from hd in ctx.TB_MyHeader
join wo in ctx.TB_AnotherTable on hd.fkId equals wo.ID
where wo.woPk == #id
orderby hd.PoItem
select hd)
.Include(h => h.TB_MyLines);
var headerPlusLines = query
.AsNoTracking()
.ToList();
return headerPlusLines;
}
The first version (V1) may not fetch children into the Nav property, depending on combinations of how ProxyCreationEnabled, LazyLoadingEnabled are set true/false.
In fact, the opposite of expected result occurs; if i set LazyLoadingEnabled = false, no children load at all;
When i would have expect it to 'dont be lazy, load it now !'
Whats going on?

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())

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

how return multiple column in join result to view model

I want to return multiple column in join result and fill in view model(VMFoodFoodMeal).
for example I want to fill VMFoodFoodMeal by Join result
Thanks
IEnumerable<VMFoodFoodMeal> _fmt = (from e in db.FoodProgramMealFood
join j in db.Foods on e.FoodId equals j.Id
select new
{
Id = e.Id,
Name = j.Name,
});
It is hard to understand what you want, but as example you can look here at Group Join section.
Here is an example code from there:
public void Linq103()
{
string[] categories = new string[]{
"Beverages",
"Condiments",
"Vegetables",
"Dairy Products",
"Seafood" };
List<Product> products = GetProductList();
var q =
from c in categories
join p in products on c equals p.Category into ps
select new { Category = c, Products = ps };
foreach (var v in q)
{
Console.WriteLine(v.Category + ":");
foreach (var p in v.Products)
{
Console.WriteLine(" " + p.ProductName);
}
}
}
result:
Beverages:
Chai
Chang
Guaraná Fantástica
Sasquatch Ale
Steeleye Stout
Côte de Blaye
Chartreuse verte
Ipoh Coffee
...
if you want to send your join Result to a model without using foreach statement you have to use this code
IEnumerable<VMFoodFoodMeal> _fmt = (from e in db.FoodProgramMealFood
join j in db.Foods on e.FoodId equals j.Id
select new VMFoodFoodMeal()
{
Id = e.Id,
Name = j.Name,
});
for example in above code I had a view model (VMFoodFoodMeal) and want to fill it by join result.
I have to make new instance of my model in select and then fill its property.
Thanks

Resources