Populating list property in ctor based on other property - c#

My application is basically just a survey with questions and multiple choice answers. Questions have Answers, but a specific Answer may lead to a specific Question being asked which might otherwise not be asked at all. e.g. "Do you like chocolate?" (if yes ask...) "Do you prefer German or Dutch chocolate?"
In the Answer class, I am trying to populate a list property "DependentQuestions" which is meant to contain id numbers for the Quesiton(s) that will be asked next if this Answer is chosen. The problem is, I am always getting nothing and I'm not sure why. I confirmed the Answer.id is zero at the time the constructor runs by populating DependentQuestions with the commented code you'll see below.
Each Question has an icollection of Answers.
Question class:
public class Question
{
[Key]
public int id { get; set; }
public string question { get; set; }
public int? DependentAnswer { get; set; }
public virtual ICollection<Answer> answers { get; set; }
}
Answer class:
public class Answer
{
[Key]
public int id { get; set; }
public string answer { get; set; }
[Required]
public int questionId { get; set; }
public List<int> DependentQuestions { get; set; }
public Answer()
{
DependentQuestions = new List<int>();
using (dbSurvey db = new dbSurvey())
{
var _list = db.Questions.Where(q => q.DependentAnswer == id).Select(q => q.id).ToList();
if (_list.Any())
{
DependentQuestions.AddRange(_list);
}
//else
//{
// DependentQuestions.Add(id);
//}
}
}
}
The "answers" collection of the Question class is being filled with the Answers to the given Question and that works just fine, but the DependentQuestions list in the Answer class is always coming up empty since Answer.id is always zero at that point. So why is Answer.id always 0, and what can I do about it?

Constructor code is run before any property values are set, so at the point of executing the constructor all properties just contain their default values. That is why it is always 0.
I am not sure what are you using as a data access framework, but generally you can do few things:
Create Answer entity with id, so you always have it in constructor:
public Answer(int id)
If that's not an option, you could also have a lazy property loading questions as needed:
class Answer
{
private List<int> _dependentQuestions;
public List<int> DependentQuestions
{
get
{
if (_dependentQuestions == null)
// load questions here
return _dependentQuestions;
}
}
}
Note that this assumes id is already set, you probably should validate that too.

Related

How do you construct an Entity class to fetch another Entity from repository?

This is a C# Question, using .NET framework built on Asp.NET Boilerplate.
Again, to re-emphasis the question being asked is "HOW...", so if an answer that was provided was a url link or a descriptive explanation on how something was supposed to be done, i would very much appreciate it. (Dont answer questions on how to tie shoelace by showing a picture of a tied shoe, nor do you answer "how to fish" by showing a recording of someone fishing...)
Since the question is pretty basic (i don't need to rephrase/repeat the header again), i'll give an example.
If i have a Forum service, and i create a class to load a Thread. Inside that thread class should be some sort of collection, array, list, or even a dbset of Post that is pulled on construct.
[Table("Thread", Schema = "dbo")]
public class ThreadModel
{
[Key]
public long Id { get; set; }
public string Title { get; set; }
//Idea 1
//Value should automatically be pulled and cached the moment class connects to database
public Post[] Posts { get; set; }
//Idea 2
//Post has a constructor to return all post that matches a thread id. While new tag keeps the return value constantly refreshed.
public Post[] Posts { get { return new Post(this.Id) } }
//Idea 3
//Not sure how collection is supposed to work. Does it automatically just pull or will i need to make a method to request?
public virtual ICollection<Post> Posts { get; set; }
//Example constructor
//When connected to database key-value pairs that match database labels will automatically get stored in class
protected ThreadModel()
{
//Idea 1-A
//Should be a value of null or empty if database yields no results
Posts = new Post();
}
public ThreadModel(int threadid) : this()
{
//Idea 1-A
Id = threadid;
//new Post => returns all posts in db
//Posts default value is all post in db
Posts = Posts.Select(post => post.threadid == this.id)
//Idea 3-A
Posts = Posts.Get(post => post.threadid == this.id)
//Idea 4
Posts = new Posts().GetThread(threadid);
}
}
Side questions
If all entities are created by inheriting Entity then at what point am i exposed to EntityFramework and DbContext?
I love this example here, submitted by a user as they attempt to connect ABP to their database. But their example doesn't show parent/child resources. I'm unable to find the guide they used to create that, and how it relates back to using ABP to fetch EntityFramework's DbContext example
How does this work? I'm unable to find instructions or explanation for this? (What am i to enter into google to get answers on these mechanics?)
[Table("AbpItems")]
public class Item : Entity
{
[ForeignKey("PostId")]
public Post Post { get; set; }
public int PostId { get; set; }
}
How does this integrate into/with abp's EntityFramework?
Where am i supposed to be creating my Database Table/Class? The project follows the Core.csproj, Application.csproj, and EntityFramework.csproj assembly layout. But it seems like every example is creating the classes at different stages or locations of the solution.
use GetAllIncluding. See https://github.com/aspnetboilerplate/aspnetboilerplate/issues/2617
Here's a complete solution ;
namespace EbicogluSoftware.Forum.Threads
{
[Table("Threads")]
public class Thread : FullAuditedEntity
{
[Required]
[StringLength(500)]
public virtual string Title { get; set; }
[Required]
[StringLength(2000)]
public virtual string Text { get; set; }
public virtual List<Post> Posts { get; set; }
public Thread()
{
Posts = new List<Post>();
}
}
[Table("Posts")]
public class Post : FullAuditedEntity
{
[Required]
[StringLength(2000)]
public virtual string Text { get; set; }
}
public class ThreadDto
{
public string Title { get; set; }
public string Text { get; set; }
public List<PostDto> Posts { get; set; }
public ThreadDto()
{
Posts = new List<PostDto>();
}
}
public class PostDto
{
public string Text { get; set; }
}
public class ThreadAppService : IApplicationService
{
private readonly IRepository<Thread> _threadRepository;
public ThreadAppService(IRepository<Thread> threadRepository)
{
_threadRepository = threadRepository;
}
public async Task<List<TenantListDto>> GetThreads()
{
var threads = await _threadRepository.GetAllIncluding(x => x.Posts).ToListAsync();
return threads.MapTo<List<TenantListDto>>();
}
}
}
Where am i supposed to be creating my Database Table/Class?
You can create them in YourProject.Core.proj

EF6 Linq Query .Include only returning first entry of child table

I would like to retrieve a list of Encounters for a Given Pokemon, as a Pokemon can be encountered in many places, so I've been trying many variants of
var currentPokemon = _context.Pokemon
.Where(mon => mon.Id == id)
.Include(mon => mon.Encounters)
.FirstOrDefault();
With the result being a Pokemon object with all of the relevant data, but only the FIRST encounter being retrieved and put into a collection resulting in this:
Looking at the database, there are about 20 encounters for caterpie, and I'd like access to all of them, but only ever just get the one.
What the Pokemon class looks like (irrelevant fields omitted):
[Table("pokemon")]
public partial class Pokemon {
public Pokemon()
{
Encounters = new HashSet<Encounters>();
}
[Column("id")]
public long Id { get; set; }
[Required]
[Column("identifier", TypeName = "VARCHAR(79)")]
public string Identifier { get; set; }
.
.
.
[InverseProperty("Pokemon")]
public virtual ICollection<Encounters> Encounters { get; set; }
}
What Encounters looks like:
public partial class Encounters {
.
.
.
[ForeignKey("PokemonId")]
[InverseProperty("Encounters")]
public virtual Pokemon Pokemon { get; set; }
}
Db data :
What am I misunderstanding here?
I think its because you are calling .FirstOrDefault(), which is only getting the first item. Can you omit that and add .ToList()? Also, var currentPokemon doesn't seem like a good variable name. You said you want a list of Encounters, right? How about var pokemonEncounters?
I think that the problem is the way that you set the relationship using ForeignKey and InverseProperty.
Try to rewrite to something like:
[Table("Pokemon")]
public class Pokemon
{
public int Id { get; set; }
public string Name { get; set; }
[InverseProperty("Pokemon")]
public ICollection<Encounter> Encounters { get; set; }
}
[Table("Enconters")]
public class Encounter
{
public int Id { get; set; }
public int PokemonId { get; set; }
[ForeignKey("PokemonId")]
public Pokemon Pokemon { get; set; }
}
My apologies, I've been looking to the wrong places for my answer. After stepping through this in a debugger, I can see that my Pokemon query does indeed return the desired result: A pokemon with many encounters attached. My problem seems to be elsewhere (specifically: the JSONified object I'm seeing come through to my web front-end truncates the encounters array to contain only the first result).
I'll post a new question with the correct problem and link to it from here when it's figured out.

Removing an element from an array in MongoDB

I am new to learning how to use MongoDB and am stuck pretty early on, so hoping someone can help me out with a simple example.
I can successfully connect to a Mongo server and create a collection and create objects to put in it. I am doing all of this through c# and the c# driver.
I have the following custom objects defined in my code.
public class Feature
{
public string FeatureName { get; set; }
public ObjectId Id { get; set; }
public List<Scenario> Scenarios { get; set; }
}
public class Scenario
{
private string _notes;
public string ScenarioName { get; set; }
public List<string> Givens { get; set; }
public List<string> Whens { get; set; }
public List<string> Thens { get; set; }
public string Explanation { get; set; }
public string Notes { get; set; }
}
As you can see, the Feature object contains a property which is a list of scenarios.
In my Mongo collection I have a Feature object that contains 3 scenarios. What I want to do in C# is write a method that can remove a specific scenario from a feature:
User provides a feature and scenario name to a method
Method checks the feature, looking through the list within it, for a scenario where the scenario.scenarioname matches the scenario name passed in to the method
If it exists, then remove the scenario from the feature and update Mongo and return a bool of true. If it doesn't exist return false
I am sure that this is probably going to be obvious when I see an example, but I have tried and get stuck trying to work through the List property looking for a property on a sub object.
I hope that all makes sense??!?
Thanks in advance.
P
Resolved it myself...
public bool DeleteScenario(string featureName, string scenarioName)
{
var collection = GetCollection<Feature>();
var query = Query.EQ("FeatureName", featureName);
var resultingFeature = collection.Find(query).SetLimit(1).FirstOrDefault();
if (resultingFeature == null)
{
return false;
}
// we have found our feature and it exists.
foreach (var scenario in resultingFeature.Scenarios)
{
if (scenario.ScenarioName == scenarioName)
{
resultingFeature.Scenarios.Remove(scenario);
collection.Save(resultingFeature);
return true;
}
}
return true;
}

Entity Framework with Dynamic Linq

Using EntityFramework context i need to search with many fields.
The EntityDBContext includes
public class Brand
{
public int BrandID { get; set; }
public string BrandName { get; set; }
public string BrandDesc { get; set; }
public string BrandUrl { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public string Name {get;set;}
public DateTime CreatedDate {get;set;}
public DateTime ExpiryDate {get;set;}
//The product class also contains many fields.(not shown here)
}
var context = new EntityDBContext();
I would like to search the brand with using the field in Product.
The fields of the product are only known at run time.
How can i build the expression to search the brand using the product fields.
Please see the screenshot.
Thanks,
Binod
First off, I'm a bit unclear on this part of your question:
the fields of the product are only known at run time.
How so? Can you elaborate on this, because I don't see a working implementation of this using EF. What is your database table (Products presumably) set up for? What properties are in that class?
We need to know that before we can give you an accurate answer. However, I'll give you a more general example, maybe that helps you in understanding.
var all_brands_that_sell_shoes = /* But not always ONLY shoes */
myDataContext.Brands
.Where(brand =>
brand.Products.Any(product =>
product.Type == "Shoe")
)
.ToList();
Edit
If I re-read your question, you don't mean that the Product class' properties are not know until runtime; but that you don't know in advance which filters need to be applied and which need to be skipped?
This second answer assumes that is what you want. Again, I don't know your class' properties since you didn't post them, so I'm inventing my own fields for the sake of example.
First, make an object like below. This will be used to aggregate all filters you wish to apply to the selection:
public class MySearchCriteria
{
public string ProductName_Contains { get; set; }
public int ProductWeight_LessThan { get; set; }
public int ProductType_Id { get; set; }
}
When you want to filter the list, you pass a MySearchCriteria object to the method:
public List<Brand> GetFilteredList(MySearchCriteria filters)
{
var brands = myDataContext.Brands; //All brands (for now)
if(filters.ProductType_Id > 0)
{
//IF the filter has a value, filter the list accordingly:
brands = brands.Where(brand => brand.Products.Any(product => product.TypeId == filters.ProductType_Id);
}
if(filters.ProductWeight_LessThan > 0)
{
//IF the filter has a value, filter the list accordingly:
brands = brands.Where(brand => brand.Products.Any(product => product.Weight < filters.ProductWeight_LessThan));
}
if(!String.IsNullOrWhiteSpace(filters.ProductName_Contains))
{
//IF the filter has a value, filter the list accordingly:
brands = brands.Where(brand => brand.Products.Any(product => product.Name.Contains(filters.ProductName_Contains)));
}
return brands.ToList();
}
This method makes sure that the list was filtered according to the SearchCriteria you provided.
If you didn't use the field filters.ProductName_Contains for example, it would be an empty string, and the if-evaluation would've prevented you from filtering based on an empty string. In the end, you would not have applied a name-based filter.
I hope this is the answer you were looking for? If not, please elaborate more as I'm having trouble understanding what it is you want then.

avoid redundant conditional statements

Using the following code, assume I have 5 different types that I might receive in the variable type. Instead of writing 5 conditional statements, is there a way to write one and use the variable "type" to dictate what the model is, in this case "CommentVote?" Or is this more a deficiency in the way I've designed the data model with each of those 5 things having a "vote" model?
if (type == "comment")
{
CommentVote voteObj = db.CommentVotes
.Where(x => x.UserID == UserID && x.CommentID == id)
.SingleOrDefault();
if (voteObj != null)
{
voteObj.Vote = vote;
db.SaveChanges();
}
else
{
CommentVote c = new CommentVote {
CommentID = id, UserID = UserID, Vote = vote, DateCreated = DateTime.Now
};
db.CommentVotes.Add(c);
db.SaveChanges();
}
count = (db.CommentVotes.Count(x => x.CommentID == id && x.Vote == true) - db.CommentVotes.Count(x => x.CommentID == id && x.Vote == false));
}
Magic Code: The stuff I would love to be able to do.
var modelName = "";
var modelOtherName = "";
if (type == "comment") {
modelName = CommentVote;
modelOtherName = CommentVotes;
}
modelName voteObj = db.modelOtherName
.Where(x => x.UserID == UserID && x.CommentID == id)
.SingleOrDefault();
Update: I'm beginning to think my model may be crap based on some of the reading referenced bellow. So I am including some of that as a reference. Let me know if that's the problem I should be trying to solve.
public class CommentVote
{
public int CommentVoteID { get; set; }
public bool Vote { get; set; }
public DateTime DateCreated { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
public int CommentID { get; set; } //This row changes from model to model
public virtual Comment Comment { get; set; } //This row changes from model to model
}
I have a handful of models that are almost identical.
As I understand you question, it more database architecture-related.
If those kind of votes are not very different from each other (in terms of properties) I woldn't use different tables for them. Instead create one Vote table with Type column and (as in the example you provided) nullable column for CommentID.
Then you can use class inheritance to reflect your votes (Vote base class and CommentedVote child class).
Table Per Hierarchy Inheritance in Entity Framework
Update:
Best is not to repeat the same propertieses in all classes. You just use inharitence like this:
public abstract class Vote
{
public int VoteID { get; set; }
public bool isVote { get; set; }
public DateTime DateCreated { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
public int VoteType { get; set;} //this property specifies type of vote (e.g. VoteType=1 for CommentedVote )
}
public class CommentVote : Vote
{
public int CommentID { get; set; }
public virtual Comment Comment { get; set; }
}
public class OtherVote : Vote
{
public int OtherID { get; set; }
public virtual Other Other { get; set; }
}
In this very good blog post you can find all possible approches. The one I'm writing about is called Table per Hierarchy (TPH).
You can absolutely reduce the code to a single statement assuming that you perform the same actions and set the same data. In this case, you should have an interface that contains the common actions and data and an object factory to instantiate the correct object based on the type.
You could do it if you implement the Factory pattern with reflection, a very basic example is shown here.
In a nutshell what you do is this: Since you have 5 different types that it could be, you would make 5 different classes that each implement a specific interface. You then create the factory class to use reflection to grab the class that is the most appropriate for your situation (be it with a straight-up class name, like in the example, or with an Attribute over the class, such as here). The factory returns an instance of that interface, which you would then just invoke the exposed method from the interface to do all of this for you.
The best part of this is that if you ever need to make another type, all you'd have to do is add another class with that attribute/name that you would be searching for in the factory. None of your other code would need to be affected, thus making you compliant with the Open/Closed Principle.

Categories