ServiceStack OrmLite Class Hierarchy in One table - ormlite-servicestack

I have a Base abstract Class and two derived classes and i want all of them to be stored in one table(Table per Hierarchy); How can i achieve this in ServiceStack OrmLite or Workaround for this issue.
public abstract class MyBaseClass
{
public String Name { get; set; }
}
public class MyDerivedClassA : MyBaseClass
{
public String Name1 { get; set; }
}
public class MyDerivedClassB : MyBaseClass
{
public String Name2 { get; set; }
}

OrmLite POCO's map 1:1 with their underlying table so all properties would need to be flattened in the base class. If you want you can use [Alias] to have all types look at the same table, i.e:
[Alias("Table")]
public abstract class MyBaseClass
{
public String Name { get; set; }
public String Name1 { get; set; }
public String Name2 { get; set; }
}
[Alias("Table")]
public class MyDerivedClassA : MyBaseClass {}
[Alias("Table")]
public class MyDerivedClassB : MyBaseClass {}
But this is rather pointless. Just map your types as they appear in the database, it's makes it much easier to reason about exactly what's happening.

Related

Why does a Required IdentityUser property result in a nullable database field?

I want to require that all entities of a particular type have a corresponding user in my ASP.NET MVC app, and that this is enforced at the database level i.e. as a non-nullable field. However, when I set the Required attribute on the IdentityUser property in my model class, like so:
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;
namespace Test.Models
{
public class Foo
{
public int Id { get; set; }
[Required]
public IdentityUser User { get; set; }
}
}
the corresponding migration that gets generated sets the UserId table field to nullable:
UserId = table.Column<string>(type: "TEXT", nullable: true)
I've read that Table Per Hierarchy can cause this, but I'm not using any kind of inheritance.
What am I missing? Is there a way to achieve what I want?
Try to fix your class
public class Foo
{
[Key]
public int Id { get; set; }
[Required]
public string UserId { get; set; }
[ForeignKey(nameof(UserId))]
public IdentityUser User { get; set; }
}
Net 5 automatically creates a shadow property UserId in order you could save your Foo class. Since you used [Required], EF automatically added that it is nullable. If this property was not able to be null (for example if it was int type ( not int? ! )) you would not need a [Required] attribute.
Also what you can do is to use Fluent API to configure your contraints.
public class Foo
{
public int Id { get; set; }
public string UserId { get; set; }
public IdentityUser User { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public DbSet<Foo> Foos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Foo>()
.HasRequired(c => c.User)
.WithMany(d => d.Foos)
.HasForeignKey(c => c.UserId);
}
}

Creating navigation code-first results in the error: does not declare a navigation property with the name

query.Include("Store_Location").Load();
throws:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: A specified Include path is not valid. The EntityType 'Model.Order' does not declare a navigation property with the name 'Store_Location'.
I used the following code in order to create the navigation code-first:
public partial class Order
{
public Nullable<int> Store_Location_ID { get; set; }
public virtual Store_Location Store_Location { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
}
public partial class Store_Location
{
public int ID { get; set; }
public virtual ICollection<Order> Orders { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
}
https://learn.microsoft.com/en-us/ef/ef6/fundamentals/relationships
Do I need to use the designer? Is there anything I need to do in order for the navigation to be created?
If you create your database with code first approach, then your entities should not be partial classes. Define them like this:
public class Order
{
public int? StoreLocationId { get; set; }
public virtual StoreLocation StoreLocation { get; set; }
}
public class StoreLocation
{
public int Id { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
Then you should create a DbContext class:
public class StoreDbContext : DbContext
{
public StoreDbContext(DbContextOptions<StoreDbContext> options) : base(options)
{
}
public virtual DbSet<StoreLocation> StoreLocations { get; set; }
public virtual DbSet<Order> Orders { get; set; }
}
After creating a context you can use the ef commands to create your database. You can read more about ef core here: https://learn.microsoft.com/en-us/ef/core/get-started/?tabs=netcore-cli
If you define your classes like I did above, you can include your navigation properties strongly typed like this:
query.Include(order => order.StoreLocation);

Localizable Entities in asp.net core

I'm using 'IStringLocalizer' in controllers to localize static data on my website! (Link)
but, What is the best approach to localize entities like NewsEntity or PostEntity?
or how to code localizable entities?
public class News : BaseEntity
{
public string Title { get; set; }
public string Body { get; set; }
}
or
{Joking}
public class News : BaseEntity
{
public string TitleEn { get; set; }
public string BodyEn { get; set; }
public string TitleDe { get; set; }
public string BodyDe { get; set; }
...
}
For this class:
public class News : BaseEntity
{
public string TitleEn { get; set; }
public string BodyEn { get; set; }
public string TitleDe { get; set; }
public string BodyDe { get; set; }
}
You could do something like this:
public class BaseEntity
{
protected bool IsGerman => Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName == "de"
}
public class News : BaseEntity
{
public string Title => IsGerman ? TitleDe : TitleEn
public string Body => IsGerman ? BodyDe : BodyEn
public string TitleEn { get; set; }
public string BodyEn { get; set; }
public string TitleDe { get; set; }
public string BodyDe { get; set; }
}
For more extensibility, you could change your database structure. Instead of News table having strings for every language. You could have a table like this:
dbo.News
TitleResource: ResourceId
BodyResource: ResourceId
dbo.Resource
ResourceId: int
dbo.Language
LanguageId: int
LanguageName: string
dbo.ResourceValue
ResourceValueId
ResourceId
Value: string
LanguageId
This way, any table that has different strings per language, instead of storing the language itself, it would store an Id to a resource for that string. And then there would be multiple ResourceValues with strings for different languages, pointing to the same Resource.
All the possible language choices would be in the Language table. This way, if you add a new language, you won't need to change a single line in the code, just add a new row in Language table, and the code should pick it up and know how to resolve strings to that language, and suggest users to fill that language.

Is it OK to declare a DBSet in the context for both a base table and a derived table?

I have a SalesOrder table which inherits from a SalesDocument table using Table Per Type Inheritance
The ( simplified) table classes are;
[Table("SalesDocumentHeaders")]
public abstract class SalesDocumentHeader
{
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
[Required]
public int CreatedByUserId { get; set; }
[Required]
public virtual DateTime? DocumentDate { get; set; }
[Required]
public String ReferenceNumber { get; set; }
}
[Table("SalesOrders")]
public class SalesOrder : SalesDocumentHeader
{
[Required]
public String CustomerOrderNumber { get; set; }
public DateTime? DeliverBy { get; set; }
public virtual SortableBindingList<SalesOrderLine> Lines { get; set; }
}
The context contains
public DbSet<SalesOrder> SalesOrders { get; set; }
public DbSet<SalesDocumentHeader> SalesDocumentHeaders { get; set; }
It doesn't strictly need the SalesOrders DBSet, since SalesOrder inherits from SalesDocumentHeader however I find it convenient.
It seems to work OK, but I am worried that there are 2 ways of reaching the same record , am I doing something wrong?
Usually you only need to keep the DBSet for the base table. This helps when you have multiple derived tables (call them A and B) and you need to decide the actual type dynamically.
For example if you have another entity which references type A or B (like a user can have different types of contact information), you can reference the base table and EF will resolve the correct concrete type at runtime. Though of course this adds some extra casting code.

How to add an additional type to the ASP.NET script manager so that the script is generated?

When I add a service reference to my script manager, all the required C# classes are generated in the script, but one. This particular class is used as follows:
[DataContract]
public class MyObject {
[DataMember]
public string Id { get; set; }
[DataMember]
public bool Value { get; set; }
}
[DataContract]
public class MyData {
[DataMember]
public string Name { get; set; }
[DataMember]
public List<MyObject> ObjectInfo { get; set; }
}
[WebService]
[ScriptService]
public class MyService {
[WebMethod(EnableSession = true)]
public void AddNewData(IEnumerable<MyData> dataObjects) {
... some code
}
}
No script is generated for the class MyObject. Am I missing something obvious?
Thanks in advance...
Try adding the GenerateScriptType attribute to your web service.
[WebService]
[ScriptService]
[GenerateScriptType(typeof(MyObject))]
public class MyService {
}
I found this in Chapter 5 (page 157) of ASP.NET AJAX in Action.

Resources