Help with strange relationship - nhibernate

I have an object called "Comment" now a Comment can be associated with a "News" article OR a "Feature" article or a "Product". So will look something like:
public class Comment
{
[BelongsTo]
public Feature Feature
{get;set;}
[BelongsTo]
public News News
{get;set;}
[BelongsTo]
public Product Product
{get;set;}
}
Now obviously only 1 Feautre, Product, or News will be populated at a time, and all implement interface "IContent". So how do I get one property like:
[BelongsTo(Type = Change type at runtime!!)]
public IContent Content
{get;set;}
Any idea how to structure this?

Use [Any]. Docs about this here and here.

Related

Unwanted loading of relations in EF Core

Hello,
I have problem with EF Core feature - It automatically binds related entities together when the entities are somewhere independently attached to current dbCotnext.
Let's assume following two entities:
public class Seller {
public Guid Id {get;set;}
public List<Product> Products {get;set;}
}
public class Product {
public Guid Id {get;set;}
public Guid SellerId {get;set;}
public Seller Seller {get;set;}
}
And some code in the controller (just for imagination):
var seller = DbContext.Sellers.FirstOrDefault(e => e.Id == someId);
var products = DbContext.Products.All(t => t.SellerId == someId);
return StatusCode(200, products);
The returned JSON will be like
[
{
"id": "1234",
"sellerId": "5678",
"seller": {
"id" : "5678",
"products": ["(muted reference loop exception from json converter here.)"]
}
}
]
But I don't want the Seller to be included in each Product. If I did, I'd call Products.Include(...) for that or something else.
I don't want to crawl through entities and null the navigation properties.
I don't want to hide it with [JsonIgnore] because sometimes the relation must be included.
I also don't want to manually detach every entity all the time when this happens.
The question is, is there any way to disable or work around this behaviour?
Thanks
No, you can't/shouldn't. You need separate dto class(es).
Newtonsoft.Json is responsible for object serialization, it decides which properties must [not] be serialized. You can control it's behavior only using it's attributes. You can't control it from EF :)
And as soon as you wish sometimes to include property and sometimes not - you need two different classes (each with correct attributes). Everything other is a hack. DTO, Automapper and all this stuff - you are welcome.
BTW, having different class(es) for external API and internal data storage allows you to easily change one without breaking other (in future).
Have you tried this configuration on Startup class:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc().AddJsonOptions(a => a.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
// other code
}
You have to change model class and using nullable type.
public class Product {
public Guid Id {get;set;}
public Guid SellerId {get;set;}
public Seller? Seller {get;set;}
}

Should I have both text and value in my model for a property that is selected from dropdownlist

In ASP.NET MVC application I have a model named CarSearchCriteria:
public class CarSearchCriteria{
public int CarMake {get;set;} // This is selected from a dropdownlist
public int YearOfFirstReg {get;set;}
public string ModelVariant {get;set}
}
I have two views - one for editing and the other one for viewing. In the editing view for the CarMake property I can do the following. I know I could have used DropDownListFor but didn't want to mess with SelectList for the time being:
<select name="CarMake">
<option value="1">BMW</option>
<option value="2">Mercedes</option>
<option value="3">Toyota</option>
</select>
So the model binding mechanism will easily bind the selected value to the appropriate model property. But what about the reading mode. I can't show 1s or 2s. I need to show BMW, Mercedes and so on. My question is what is the preferred way, do I have to have a property name that holds the actual textual information, something like CarMakeText?
You could have both the identifier (which you currently have) as well as the Make object itself. The latter would never need to be accessed when building the model, but can be accessed when reading the model. A lazy-loaded read-only property often works well for that. Something like this:
public int CarMakeID { get; set; }
public Make CarMake
{
get
{
if (CarMakeID == default(int))
return null;
// fetch the Make from data and return it
}
}
Naturally, this depends a lot on what a Make actually is and where you get it. If there's just some in-memory list somewhere then that should work fine. If fetching an instance of a Make is a little more of an operation (say, fetching from a database) then maybe some in-object caching would be in order in case you need to access it more than once:
public int CarMakeID { get; set; }
private Make _carMake;
public Make CarMake
{
get
{
if (CarMakeID == default(int))
return null;
if (_carMake == null)
// fetch the Make from data and save it to _carMake
return _carMake;
}
}
David's solution is just fine but for some reason I find my own solution to better fit my needs and besides that I find it more elegant. So basically what I do is I create a class that holds the textual descriptions of all the properties that keep just ID. For example, I have the following model:
public class EmployeeModel{
public int EmployeeID {get;set;}
public string FullName {get;set}
*public int DepartmentID {get;set}
*public int SpecialityID {get;set;}
public int Age {get;set;}
}
The properties marked with asterisk are the properties that keep ids of possible many predefined options and when showing we're supposed to show the actual descriptions, not the number representations. So for this purpose, we create a separate class:
public class EmployeeTextValues{
public string DepartmentName {get;set;}
public string SpecialityName {get;set;}
}
And then I just add this class as a property to my model:
public EmployeeTextValues TextValues {get;set;}
After that, it's quite easy to access it from anywhere, including Razor.
P.S. I'm sure that a lot of people will tend to do the following before initializing this property:
Employee emp=new Employee;
emp.Age=25;
emp.TextValues.DepartmentName="Engineering";// Don't do this
If you try to access or set Textvalues.Someproperty you'll get Object reference not set to an instance of an object. So do not forget to set TextValues first to some initialized object. Just a kind reminder, that's all.

How to prevent Nhibernate from fetching derived class?

I am using Nhibernate and I have a problem when fetching a base class with multiple derived classes (each class mapping a different table). When I watch the request, Nhibernate joins on every derived tables which has a huge an impact on the performances...
Here is a simplified vision of my classes :
public class Animal{
public virtual int ID { get; set;}
public virtual string Name { get; set;}
}
public class Dog : Animal{
//others properties
}
public class Cat: Animal{
//others properties
}
public class Person{
public virtual int ID { get; set;}
public virtual IEnumerable<Animal> Animals { get; set;}
}
A person has a list of Animals and I just want their names. The example is not perfect and more it's more complicated (a banking program) but it reflect well my problematic.
I KNOW it can be done differently etc, but it is a legacy so I don't have a choice...
Thanks in advance.
IMO NHibernate will only joind tables which contain projected columns. define a query but do not return Person but project into a dto/anonymous class the properties you need
After all, I created a class AnimalBase which is inherited by Dog, Cat and so forth and a class Animal without any child (both having the interface IAnimal).
As in 95% of my request, I only need Animal, I reference this class in my other objects like Person.
Not perfect but I did not find anything better...
Thanks Firo for your help.

How can ServiceStack.OrmLite ignore a property by attribute

public class User
{
public long Id {get;set;}
[References(typeof(City))]
public long CityId {get;set;}
[????]
public City {get;set;}
}
I'm trying to use ServiceStack.OrmLite. I'm using both ReferenceKey(CityId) and Reference (City). ReferenceKey is for Db creation, Reference is for using object in my code.
IgnoreAttribute .. Tested, it works.
Try the [IgnoreDataMember] attribute.
This attribute will tell the ServiceStack libraries to ignore this property.

Fluent NHibernate & one-to-one

For a (very) long time I've been looking for an example on how to correctly implement a one-to-one mapping with Fluent NHibernate.
Most resources I find say:
I think you mean a many-to-one
However no one actually gives an example on how to correctly implement the one-to-one relation.
So, could you give an one-to-one mapping example with Fluent NHibernate?
Note: I'm not interested in people saying "what's your model, you might actually need HasMany". No, thanks, I simply need a one-to-one example.
To be more precise, I know the syntax. That's the only thing I could find by searching by myself. What I'm looking for is a more complete example, including a ((very) simple) database setup, and the whole mapping, of all entities that participate in the relationship, which I think would have reasonable size for Stack Overflow.
I've solved my problem.
I've also written a somewhat detailed article on this problem, that you can find at: http://brunoreis.com/tech/fluent-nhibernate-hasone-how-implement-one-to-one-relationship/index.html
You will find a scenario in which we want a one-to-one relationship, the database schema as we would like it, the code of the model as it needs to be to meet NHibernate requirements, and the Fluent mapping that corresponds to the situation.
these are the two classes.
public class A
{
public virtual int Id {get;set;}
public virtual string P1 {get;set;}
public virtual string P2 {get;set;}
public virtual string P3 {get;set;}
public virtual B child { get; set; }
}
public class B
{
public virtual int Id {get;set;}
public virtual string P4 {get;set;}
public virtual string P5 {get;set;}
public virtual string P6 {get;set;}
public virtual A parent;
}
this should be added in the fluent configuration.
public AMap()
{
/* mapping for id and properties here */
HasOne(x => x.child)
.Cascade.All();
}
public BMap()
{
/* mapping for id and properties here */
References(x => x.parent)
.Unique();
}
This is the best example I've seen. Hopefully it meets your needs.
HasOne(x => x.Prop)