Data annotation in Servicestack References vs ForeignKey - servicestack

Well, in ServiceStack
where can I read up on the merits and differences of
[References(typeof(ABC))] and
[ForeignKey(typeof(XYZ) ]
What are they used for ? (I know, rather naively put but I have a hard time finding the basic description)

The docs for both are referenced throughout ServiceStack.OrmLite project page.
Use either for simple Foreign Keys
Essentially they're both equivalent to define simple Foreign Keys which you can use either for:
[References(typeof(ForeignKeyTable1))]
public int SimpleForeignKey { get; set; }
[ForeignKey(typeof(ForeignKeyTable1))]
public int SimpleForeignKey { get; set; }
The [References] attribute is also used by other data persistence libraries like PocoDynamo for DynamoDb where it would be preferred when wanting to re-use your existing data models else where, it's also useful as a benign "marker" attribute on different models when you want to include a navigable reference to an associated type for the property.
Fine-grained Foreign Key options
The [ForeignKey] is specific to OrmLite and includes additional fine-grained options for defining foreign key relationships specific to RDBMS's like different cascading options, e.g:
public class TableWithAllCascadeOptions
{
[AutoIncrement] public int Id { get; set; }
[ForeignKey(typeof(ForeignKeyTable1))]
public int SimpleForeignKey { get; set; }
[ForeignKey(typeof(ForeignKeyTable2), OnDelete = "CASCADE", OnUpdate = "CASCADE")]
public int? CascadeOnUpdateOrDelete { get; set; }
[ForeignKey(typeof(ForeignKeyTable3), OnDelete = "NO ACTION")]
public int? NoActionOnCascade { get; set; }
[Default(typeof(int), "17")]
[ForeignKey(typeof(ForeignKeyTable4), OnDelete = "SET DEFAULT")]
public int SetToDefaultValueOnDelete { get; set; }
[ForeignKey(typeof(ForeignKeyTable5), OnDelete = "SET NULL")]
public int? SetToNullOnDelete { get; set; }
}

Related

Servicestack - possibility of mapping several POCO to one table

I'm looking for a way to map several POCO objects into single table in the ServiceStack.
Is it possible to do this in a clean way, without "hacking" table creation process?
As a general rule, In OrmLite: 1 Class = 1 Table.
But I'm not clear what you mean my "map several POCO objects into single table", it sounds like using Auto Mapping to populate a table with multiple POCO instances, e.g:
var row = db.SingleById<Table>(id);
row.PopulateWithNonDefaultValues(instance1);
row.PopulateWithNonDefaultValues(instance2);
db.Update(row);
If you need to maintain a single table and have other "sub" classes that maintain different table in the universal table you can use [Alias] so all Update/Select/Insert's reference the same table, e.g:
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
[Alias(nameof(Poco))]
public class PocoName
{
public int Id { get; set; }
public string Name { get; set; }
}
[Alias(nameof(Poco))]
public class PocoAge
{
public int Id { get; set; }
public int Age { get; set; }
}
Although I don't really see the benefit over having a single table that you use AutoMapping to map your other classes to before using that in OrmLite.

Automapper - flattening of object property

let's say I have
public class EFObject
{
public int Id { get; set; }
public int NavId { get; set; }
public NavObject Nav { get; set; }
}
public class DTOObject
{
public int Id { get; set; }
public int NavId { get; set; }
public string NavName { get; set; }
}
My expectation was high, and I thought to my self the built-in flattening should handle this, so my mapping is very simple
CreateMap<DTOObject, EFObject>().ReverseMap();
Unfortunately, converting DTOObject to EFObject does not work as expected because EFObject.Nav is null. Since I used the name NavId and NavName I would expect it to create a new NavObject and set the Nav.Id and Nav.Name accordingly.
My Problem : Is there a feature in Automapper that will allow me to achieve the intended result without having to manually write a rule to create an NavObject when mapping the Nav property?.
Unflattening is only configured for ReverseMap. If you want unflattening, you must configure Entity -> Dto then call ReverseMap to create an unflattening type map configuration from the Dto -> Entity.
as noted by Automapper documentation here

Foreign key for same table in Web Api 2

I have a data model that has a folder structure defined through the data. Various objects can be in these folders, including folders themselves, similarly to how folders in Explorer cascade and can contain each other.
I think I've figured out how foreign keys work in this stack, but when I go to migrate it to the database, the system won't let me. What's the issue? There's got to be a way to nest these folder entries inside each other, right?
namespace api.Models
{
public class Folder
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int SuperFolderId { get; set; }
public Folder SuperFolder { get; set; }
}
}
The oversight here is that self-referencing foreign keys can't be nullable. Imagine a file structure where EVERY folder needs a superfolder. It would either go up forever, or two folders would have to reference each other and it would loop.
It's the same as the classic self-referencing key example of Employees having Managers, where Managers are also on the Employee table. You can only go so far up the chain before you reach the head of the company.
The system assumes foreign keys are not nullable, and so it makes them required without the need of the [Required] attribute. It is sometimes valid to make a foreign key optional, and to do that, you turn the int into a nullable int, or "int?". The code below fixes the problem.
namespace api.Models
{
public class Folder
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int? SuperFolderId { get; set; }
public Folder SuperFolder { get; set; }
}
}

How to design DTO classes for nested domain objects?

I am new to using DTOs.
I have two domain classes:
Category
Product
as follows
public class Category
{
// Properties
public int Id { get; set; }
public string Name { get; set; }
// Navigation properties
public virtual Category ParentCategory { get; set; }
// Foreign key
public int? ParentCategoryId { get; set; }
// Collections
public virtual ICollection<Product> Products { get; set; }
public virtual ICollection<Category> Subcategories { get; set; }
}
public class Product
{
// Properties
public int Id { get; set; }
public string Name { get; set; }
// Navigation property
public virtual Category Category { get; set; }
// Foreign key
public int CategoryId { get; set; }
}
I want to use Automapper.
I am not sure how to design DTOs for the above aggregate (graph).
Should CategoryDTO have a collection of type ProductDTO or a collection of type Product?
Should ProductDTO have a CategoryDTO as navigation property or a Category or just an Id to the Category?
Can anyone suggest the code for DTOs?
How should this structure be flattened (if it should) and mapped to domain classes?
Many thanks in advance.
I design my DTOs to be only the data used for a specific controller action for MVC. Typically this means if I have a CategoryController, then I have a CategoryIndexModel, CategoryDetailsModel, CategoryEditModel etc etc. Only include the information you want on that screen. I flatten as much as I can, I don't create child DTOs unless I have a Partial or collection.

Validation error with foreign key

When I have this simple model:
public class User
{
// Primary key
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid UserId { get; set; }
[Required]
public Int32 FailedPasswordAttemptCount { get; set; }
[Required]
public Language Language { get; set; }
}
public class Language
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid LanguageId { get; set; }
[MaxLength(30)]
public String LocaleName { get; set; }
}
And I do this code:
var user = context.Users.Single(u => u.UserId == userId);
user.FailedPasswordAttemptCount++;
context.SaveChanges();
It will throw an DbEntityValidationException expception The Language field is required..
Technically this is true because the property is marked as required and because the Language property is null when fetched from the database (no lazy or eager loading).
But how do I change this behaviour?
I don't want to disable validation completely
I don't want to lazy / eager load the field
I don't want to remove the Required tag from the model
What other options are out there?
You can prevent this by adding the primitive FK field (probably LanguageId) to your User class. This is not uncommon in entity framework. There are more occasions where getting or setting the primitive property saves work or unnecessary (lazy) loading.

Resources