I am trying to create a list of custom objects in LINQ, and I am not sure how to do it. Here is my classes...
public class MenuModel
{
public IList<MenuCategoriesWithArticles> Menu { get; set; }
}
public class MenuCategoriesWithArticles
{
public Category Category { get; set; }
public IList<Article> Articles { get; set; }
}
and I would like to create MenuModel from the following functions that return Category and IList in order.
businessCategory.GetAllCategories();
businessArticle.GetArticlesByCategory(int categoryId);
I have something like below but I am not sure...
businessCategory.GetAllCategories().Select(x=> new .....)
any help would be great. I dont want to loop to get each categories' articles.
Maybe something like this could help you.
businessCategory.GetAllCategories().Select(x=> new MenuCategoriesWithArticles{
Category = x,
Articles = businessArticle.GetArticlesByCategory(x.categoryId).ToList();
});
The only thing is, if GetArticlesByCategory does a database search this code won't be optimal; if that is the case, you should query all the articles separately depending on the categories you select first.
I assume you are using Entity Framework.
The best approach for you will be to create a relationship between articles and category in your sql server, change your classes that represent table to have references to each other, and let you context know about it.
public class Category
{
public int CategoryId { get; set; }
public IList<Article> Articles { get; set; }
}
public class Article
{
public int ArticleId { get; set; }
public Category Category { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>().HasOne(article => article.Category)
.WithMany(category=> category.Articles);
}
When you have this changes, you can get your categories this way.
await dbContext.Category.Include("Articles").ToListAsync()
After executing, your Category object will have list of Articles. You can find more info here http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx
Related
I want to make a tree structured product category view. I have found this article by Ole Michelsen from 2011, which I think looks promising. The article describes a method similar to what I almost had in mind, using Razor to recursively render the tree structure.
My database table is almost identical to the one described in the article:
[ProductCategory]
Id
ParentId
Title
I'm not sure what my view model should look like. Should it be an IEnumerable of ProductCategory, or should it be an instance of ProductCategory and have an IEnumerable of ProductCategories in it?
Something like this ...
public class ViewModelProductCategory
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public int SortOrder { get; set; }
public int NumOfProducts { get; set; }
}
... or more like this?
public class ViewModelProductCategory
{
public IEnumerable<ProductCategory> ProductCategory { get; set; }
//public int NumOfProducts { get; set; }//<--Not too sure about this property
public IEnumerable<Product> Products { get; set; }
}
If the second one is closer to the "correct" one, how can I have SortOrder and NumOfProducts (how many products are in the current category)?
And the thing I'm most confused about, is how the razor rendering comes together. How do I send the viewmodel to the recursive partial view, and how does the partial view know which item to render?
I have some razor-code, but I can guarantee that posting it will NOT make anything clearer as of what I'm trying to achieve.
This pseudo-code is perhaps more describing:
_recursivePartial.cshtml
#model [my unknown viewmodel goes here, is it IEnumerable or not?]
<ul>
foreach item in model
{
<li>#Html.Partial("_recursivePartial.cshtml", [what goes here?])
// 1: How does _recursivePartial.cshtml know where in the tree it is?
// 2: How does this structure relate to the data structure in the DB?
}
</ul>
I’m not sure there is a “correct” way of doing things, but I like to keep my database models different to the view models. I often use AutoMapper to get the data between models.
In your situation I’d probably have two View Models:
public class ProductCategoryItemModel
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public int SortOrder { get; set; }
public int NumOfProducts { get; set; }
}
and
public class ProductCategoriesModel
{
public List<ProductCategoryItemModel> Categories { get; set; }
}
I always convert ToList() rather than passing an IEnumerable to views, but again I’m not sure that’s the “correct” way.
I am trying to create a generic function to add relational records in entity framework. I am working on the following solution. Though if I am going about this all wrong could you direct me in the right direction.
I have the following to classes. Also to note this is a code first approach in entity framework.
public class MainTable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MainTableID { get; set; }
public int LookupID { get; set; }
[ForeignKey("LookupID")]
public virtual LookupTable Lookups { get; set; }
}
public class LookupTable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int LookupID{ get; set; }
public string LookupText { get; set; }
public virtual ICollection<MainTable> MainTable { get; set; }
}
I then have the following code that I am trying to add an relationship between MainTable and LookupTable. I am first passing the two table class types and passing the record to add and the name of the collection property.
The problem is the "collectionField" is NULL whenever I try to cast it (ICollection(MainTable)). I need to "collectionField" to become of type ICollection(MainTable) so I can add the MainTable record, unless I am going about this the wrong way.
public void AddRelationalRecord<MainTableType, LookupTableType>(MainTableType recordToAdd, string collectionFieldName)
where MainTableType: class
where LookupTableType: class
{
var collectionField = typeof(LookupTableType)
.GetProperties()
.Where(prop => prop.Name == collectionFieldName)
.FirstOrDefault();
collectionField.Add(recordToAdd);
}
From the comments I've decided to change my approach to this. If anyone is interested the below code works.
public void AddRelationalRecord(object recordToAdd, object recordWithCollection, string collectionFieldName)
{
var collectionProp = recordWithCollection.GetType().GetProperty(fieldName);
collectionProp.PropertyType.GetMethod("Add").Invoke(aaa.GetValue(recordWithCollection, null), new object[] { recordToAdd });
}
I'm working on a recommendation algorithm which all works fine. But now I wanted to implement this code into the branch of my development team.
I'll start from the top. My algorithm can recommend 2 types of objects, restaurants and dishes.
Restaurant:
public class Restaurant
{
public Guid Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public List<Tag> Tags { get; set; } = new List<Tag>();
public int PriceRange { get; set; }
}
And dish:
public class Dish
{
public Guid Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public virtual Restaurant rest { get; set; }
[ForeignKey("rest")]
public Guid RestaurantId { get; set; }
public List<Tag> Tags { get; set; }
}
Now my product owner wants the list to be like this when it's being presented on the home page of our app:
[Restaurant][Dish][Restaurant][Dish] Etc...
So basically, he wants to alternate the type of object that's being recommended. These dishes and restaurants are completely separate. They are generated by my algorithm purely on the user's preferences and have no correlation with eachother at all.
Now my problem is how to return such a list. I figured I'd need a wrapper class which contains either a Restaurant or Dish like this:
public class RecommenderItem
{
public Restaurant rest { get; set; }
public Dish dish { get; set; }
}
This way I can create a List<RecommenderItem> and return that to the client. The client would only need to check which attribute is null and retrieve the values from the one that is not.
I'm just unsure if this is the correct approach. Are there any 'best practices' in doing this? Let me know if I should elaborate more!
If they doesn't have common base class then creating one wrapper class is the best solution. At the same time you can be more flexible and create something like
public class RecommendationItem
{
public Guid Id { get; set; }
public string Name { get; set; }
public string PageUrl { get; set; }
public object Entity { get; set; }
}
So you can include all common information in this class and client will not be required to check with which object type he works. In such case it would be easier to add one more item type. At the same type I added reference to entity itself - it can be used if some specific handling for one or two item types is required.
You can declare an interface IRecommenderItem:
public interface IRecommenderItem
{
//shared properties
}
public class Restaurant : IRecommenderItem
{
}
public class Dish : IRecommenderItem
{
}
than, you can type:
List<IRecommenderItem> m = new List<IRecommenderItem>();
If you are going to connect pairs of elements it always makes sense to me to... well, pair the elements. I am assuming that each dish is specific to a particular restaurant? So the list would be [Restaurant1][Dish for Restaurant1][Restaurant2][Dish for Restaurant2]...?
I like the previous answer by oryol creating a common base class as well.
So, your RecommenderItem class is fine. But fill in both properties and pass a list of pairs back. Expand the list into the full set of items for display by creating a new List, iterating through the list of RecommenderItems and adding Restaurant and Dish from each entry in it.
I have some hierarchal data. The Model class I use looks like this:
public class Category
{
[Key]
public int CategoryID { get; set; }
[Required]
[StringLength(64)]
public string Name { get; set; }
public int? ParentCategoryID { get; set; }
[ForeignKey("ParentCategoryID")]
public Category ParentCategory { get; set; }
[Required]
public int ListOrder { get; set; }
// left/right
public int TreeLeft { get; set; }
public int TreeRight { get; set; }
} // eo class Category
I've used the techniques outlined here to store my data, and inserting and retrieving data is not a problem.
What I would like to do, is add a Category collection to this class:
public virtual IEnumerable<Category> {get; set; }
I've used this technique in the past (learned from the Mvc tutorials), to include related tables when getting data. However, when I tried this I received an error with regard to IEnumerable<> being abstract (which is understandable, I guess the framework couldn't figure out what I want to do)...
... and indeed, being new to LINQ, I have no idea what the LINQ would look like that would give me back a collection of Category instances each of which had their children inside them.
If it's not possible I guess I can construct the list manually, use a regular LINQ query to get all the categories at a particular position (and their children) and manually populate it all.
I was wondering if LINQ could do this for me?
Thanks in advance!
If you have a self reference fk than the collection should be generated automatically when you add the table to the dbml file
And will look something like this:
[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Category_Category", Storage="Categories", ThisKey="pkCategoryID", OtherKey="ParentCategoryID")]
public EntitySet<Category> Categories
{
get
{
return this._Categories;
}
set
{
this._Categories.Assign(value);
}
}
Dont use IEnumerable<Category> but Collection<Category> . If that is your problem..
I'm prototyping my first MVC application, it's a simple forum. I've done part of the domain model and I'm trying to figure out how to do something that's pretty basic in SQL alone, but I can't figure it out in my application. Here are my Entities:
[Table(Name="Users")]
public class User
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public int Id { get; set; }
[Column] public string Username { get; set; }
[Column] public string Password { get; set; }
[Column] public string PasswordHash { get; set; }
[Column] public string PasswordSalt { get; set; }
[Column] public string FirstName { get; set; }
[Column] public string LastName { get; set; }
public List<Forum> AllowedForums { get; set; }
[Column] public DateTime LastLogin { get; set; }
[Column] public DateTime MemberSince { get; set; }
}
[Table(Name="Forums")]
public class Forum
{
[Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)]
public int Id { get; set; }
[Column] public int ParentId { get; set; }
[Column] public string Title { get; set; }
[Column] public string Description { get; set; }
[Column] public bool IsGlobal { get; set; }
[Column] public int DisplayOrder { get; set; }
}
I also have a linking table called AllowedForums that looks like:
userid forumid
1 4
In order to select the forums that a user is allowed to view and forums where IsGlobal == true I'd do this in SQL:
SELECT * FROM Forums
LEFT OUTER JOIN AllowedForums ON Forums.id = AllowedForums.Forumid
WHERE AllowedForums.Userid = 1
OR Forums.IsGlobal = 1
How should I populate the
public List<Forum> AllowedForums
field using C#/Linq to SQL?
Should AllowedForum be a value object with its own table mapping? That seems like overkill but I could easily join on it. I looked briefly at EntitySet but the simple example I saw didn't seem to fit. It feels like there should be an elegant way to get a collection of Forum objects for each User, but I can't come up with any. BTW, I'm new to C# & OO. I should also mention that since these are the early stages of the app, I'm open to changing the structure/relationships of the entities or tables if there's a better approach I'm not seeing.
You should have another Entity class (probably should be internal) that mirrors your AllowedForums table in the database. Now I'm assuming your User table and your Forums table both have PK/FK relationships to this AllowedForums table. Therefore, there should be an internal property on the User class that looks like this:
internal EntitySet<AllowedForums> AllowedForumsRelationships
{
get;set;
}
Or something like that. This should be on both the User and Forums class. Your AllowedForums class will have two properties on it. One for User and one for Forum. (If you use the LINQ to SQL designer, all this will happen for you automatically).
Once you have that, if you want to get all the AllowedForums for a user you can do something like this:
public IList<Forum> AllowedForums
{
get
{
var result = new List<Forum>();
foreach(var relationShip in this.AllowedForumsRelationships)
{
result.Add(relationShip.Forum);
return result;
}
}
}
This is some rough code I just banged out, and I'm not sure it's 100% accurate, but I think you'll get the idea. Basically you're dealing with a many to many relationship which is always a pain.
EDIT: I just messed with this idea with the Northwind Database with these tables:
Orders
OrderDetails
Products
There's a many to many relationship there: An order can have multiple products, and a product can belong to many orders. Now say you want to get all products for an order:
public partial class Order
{
public IList<Product> Products
{
get
{
var list = new List<Product>();
foreach (var item in this.Order_Details)
{
list.Add(item.Product);
}
return list;
}
}
}
That works, so it should work in the scenario you're talking about as well.
Something like:
var AllowedForums = from f in ForumsTable
join af in AllowedForumsTable on f.Id equals af.forumid into temp
from aft in temp.DefaultIfEmpty()
where (f.IsGlobal == 1 || aft.userid == 1)
select f;