How to bind Product and Item in Entity Framework? - linq

I have binding into the class, but not in another. I can`t call Product from Item: Object reference not set to an instance of an object.
Whats wrong?
How optimize this code?
foreach (var xd in excelData)
{
Product p = new Product {
Name = xd.ProductName,
};
ctx.Products.Add(p);
ctx.SaveChanges();
Item t = new Item {
Product=p,
};
t.ProductId = t.Product.ProductId;
ctx.Items.Add(t);
ctx.SaveChanges();
t.Product = ctx.Products.Where(c => c.ProductId == t.ProductId).FirstOrDefault();
ctx.SaveChanges();
}

Assuming your ProducId and ItemIdare auto generated you can write this with a single call toSaveChanges` as follows
foreach (var xd in excelData)
{
Product p = new Product {
Name = xd.ProductName,
};
Item t = new Item {
Product=p,
};
ctx.Items.Add(t);
}
ctx.SaveChanges();

ObjectQuery.Include Method. Specifies the related objects to include in the query results.
ctx.Items.Include("Product").Where(c => c.SupplierId == id).ToList().ForEach(t =>
{
li.Add(new ShortPricesListItem()
{
Name = t.Product.Name,
});
});

Related

Load multipe sharepoint list item fields in one Go using CSOM c#

***ctx.Load(listItemCollection,
eachItem => eachItem.Include(
item => item,
item => item["Column1"],
item => item["Column2"]
));***
i have list of fields in a array of string instead of column1 and column2, how can i pass it through in include linq, not able to create proper lambda on runtime. i tried following ways but couldn't get success. Static befor loops works but thw fields added in loop fails as it doesn't evaluate string value in loop
***Expression<Func<ListItem, object>>[] paramss = new
Expression<Func<ListItem, object>>[length];
paramss[0] = x => x.ContentType;
paramss[1] = x => x["Title"];
count = 2;
foreach (string item in solConnDefModel.Columns)
{ paramss[count] = x => x[item];
count++;
}***
Please take a reference of below code:
List dlist = context.Web.Lists.GetByTitle("listname");
context.Load(dlist);
context.ExecuteQuery();
string[] fieldNames = { "Id", "Title", "num", "mStartDate" };
// Create the expression used to define the fields to be included
List<Expression<Func<ListItemCollection, object>>> fieldsToBeIncluded = new List<Expression<Func<ListItemCollection, object>>>();
foreach (string s in fieldNames)
{
fieldsToBeIncluded.Add(items => items.Include(item => item[s]));
}
// Initialize the collection of list items
var listItems = dlist.GetItems(new CamlQuery());
context.Load(listItems, fieldsToBeIncluded.ToArray());
context.ExecuteQuery();
You can hover on load method to see what type parameter it requires, then generate a corresponding one and pass it.
i have to create lambda expression at runtime. following code i was able to get expected value
Expression<Func<ListItem, object>>[] paramss = new Expression<Func<ListItem, object>>[length];
foreach (string item in Columns)
{
if (item.ToLower() != "contenttype")
{
ParameterExpression parameter = Expression.Parameter(typeof(ListItem), "x");
var propertyInfo = typeof(ListItem).GetMethod("get_Item");
var arguments = new List<Expression> { Expression.Constant(item) };
var expression = Expression.Call(parameter, propertyInfo, arguments);
var lambda = Expression.Lambda<Func<ListItem, object>>(expression, parameter);
paramss[count] = lambda;
}
else
{
paramss[count] = x => x.ContentType;
}
count++;
}

list inside another list select

what is the correct syntax to write the second list? bookid and other fields are not recognizing
var bookssublist = from bookdetails in bookslist
join bookcategories in _context.BookCategories
on bookdetails.BookId equals bookcategories.BookId
where bookcategories.CategoryId==CategoryId
select new BookBasicInfo {
count = bookcount,
BookInfo = new List<BookInfo>()
{
BookId = bookdetails.BookId,
BookTitle = bookdetails.Title,
Images = bookdetails.ThumbnailImagePath,
PublishDate = bookdetails.PublishedDate,
AuthorList = bookdetails.BookAuthors.Select(q => q.Author.Author1).ToList(),
CategoryList =bookdetails.BookCategories.Select(q=>q.Category.CategoryName).ToList(),
}
};
You are using collection initializer in a wrong way. Actually, you forgot to pass an object of type BookInfo to the initializer.
BookInfo = new List<BookInfo>()
{
new BookInfo()
{
BookId = bookdetails.BookId,
BookTitle = bookdetails.Title,
Images = bookdetails.ThumbnailImagePath,
PublishDate = bookdetails.PublishedDate,
AuthorList = bookdetails.BookAuthors.Select(q => q.Author.Author1).ToList(),
CategoryList =bookdetails.BookCategories.Select(q=>q.Category.CategoryName).ToList()
}
}

how to select collection type navigation property's value

I have 3 tables, team(id,name) player(id,teamid,name) playerdetail(id,playerid,height,weight), the relationship between team and player is one to many, the relationship between player and playerdetail is one to one.
I want to use eager loading to load all the information and print out the name of players who is higher than 2 meters.
I have write the code below,
using (var context = new TestEntities())
{
var query = from t in context.Teams.Include("Players.PlayerDetails") select t;
foreach (var v in query)
{
Console.WriteLine(v.Players.Any(x => x.PlayerDetails.Any(y => y.Height > 200)));
}
Console.Read();
}
It prints out only true and false, how can I modify it and make it print out the name of player?
Thanks in advance
Why don't you just query the players through context.Players like below?
using (var context = new TestEntities())
{
var query = context.Players.Include("Team").Include("PlayerDetails")
.Where(p => p.Height > 200);
foreach (var v in query)
{
Console.WriteLine(v.Name);
}
Console.Read();
}

Linq to SQL construct a custom object externally - join from another object

Continued from this solution (thanks Daniel Hilgarth)
return db.Tags.Select(ConstructTagItem());
And the method:
private Expression<Func<Tag, TagItem>> ConstructTagItem()
{
return a => new TagItem {ID = a.Id Name = a.Name };
}
Additional question, how do i use it in this scenario then:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = new TagItem
{
ID = c.Tag.Id,
Name = c.Tag.Name
}
});
I want to reuse the method from the other answer:
private Expression<Func<Tag, TagItem>> ConstructTagItem
{
get { return a => new TagItem {ID = a.Id Name = a.Name }; }
}
To construct something like this:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = ConstructTagItem // TODO: need some way to tell the method that it should use c.Tag
});
I want to use the same construction of my TagItem multiple places. This will make it easier if the object changes, and save lines.
I guess that I somehow have to define that it is c.Tag into ConstructTagItem(), but I really don't know much about expressions yet. So i hope that someone is able to help?
I'm not sure if I have a full handle on what you're trying to do. What does "use it in this scenario" mean? Can you mimic your previous technique with something like this in order to encapsulate creating a NewsTagItem, or is it something else you're trying to achieve?
private Expression<Func<News_Attribute, NewsTagItem>> ConstructNewsTagItem()
{
return c => new NewsTagItem
{
NewsID = c.News_Id,
Name = a.Name
TagID = c.Tag_Id,
Content = c.Content,
Attribute = new TagItem
{
ID = c.Tag.Id,
Name = c.Tag.Name
}
}
});
db.News_Attributes.Select(ConstructNewsTagItem());
UPDATE:
OK, we can't directly re-use your ConstructTagItem() because it returns an expression containing a function. What you need is a MemberInitExpression. It's a little tricky to create by hand, but we can use a trick whereby we create the expression we desire wrapped with a thunk, so that it isn't evaluated, and then grab the body of the thunk to get the expression. See the snippet below:
private Expression GenerateNewTagItem(TagItem c)
{
Expression<Func<TagItem>> expr = () => new TagItem { ID = c.ID, Name = c.Name };
return expr.Body;
}
With this function, we can now do pretty much exactly what you want:
return (from c in db.News_Attributes
select new NewsTagItem
{
NewsID = c.News_Id,
TagID = c.Tag_Id,
Content = c.Content,
Attribute = GenerateNewTagItem(c)
});
Pretty neat right?

Iterating tables in a context and the properties of those tables

I'm iterating the tables of a context and then the properties of those tables to eager load all columns in a context. I received some help via another question, but I don't seem to be able to figure out how to iterate the column properties of the actual table.
Final working code:
public static void DisableLazyLoading(this DataContext context)
{
DataLoadOptions options = new DataLoadOptions();
var contextTables = context.GetType().GetProperties().Where(n => n.PropertyType.Name == "Table`1");
foreach (var contextTable in contextTables)
{
var tableType = contextTable.GetValue(context, null).GetType().GetGenericArguments()[0];
var tableProperties = tableType.GetProperties().Where(n => n.PropertyType.Name != "EntitySet`1");
foreach (var tableProperty in tableProperties)
{
ParameterExpression paramExp = Expression.Parameter(tableType, "s");
Expression expr = Expression.Property(paramExp, tableProperty.Name);
options.LoadWith(Expression.Lambda(expr, paramExp));
}
}
context.LoadOptions = options;
}
You're only getting the ProperInfos. You need to get the values from the PropertyInfos:
var tablePropertInfos = context.GetType().GetProperties().Where(
n => n.PropertyType.Name == "Table`1");
foreach (var tablePropertyInfo in tablePropertInfos)
{
// Get the actual table
var table = tablePropertyInfo.GetValue(context, null);
// Do the same for the actual table properties
}
Once you have the PropertyInfo class, you need to get the value using the GetValue method.

Resources