ServiceStack OrmLite - database first & multiple primary keys - servicestack

I have to work off an existing Db & would like to use ServiceStack's OrmLite.
Thus I have created Poco classes, using OrmLite T4 templates.
ISSUE: I would like to save to a table which has multiple primary keys.
public partial class DbUserGroup
{
[Required]
public int Userid { get; set;} // this is a primary key
[Required]
public int Groupid { get; set;} // this is a primary key
public int Ranking { get; set;}
public bool Isprimary { get; set;}
}
Currently using Db.Save(userGroup) does not work. Is there any way of addressing this using ServiceStack's OrmLite.

Multiple primary keys don't exist. A multi-column primary key yes.
Please take a look on this link https://github.com/ServiceStack/ServiceStack.OrmLite#limitations
As it said
A potential workaround to support tables with multiple primary keys is to create an auto generated Id property that returns a unique value based on all the primary key fields

I resolved it by adding [PrimaryKey] to both properties.
public partial class DbUserGroup
{
[Required]
[PrimaryKey]
public int Userid { get; set;} // this is a primary key
[Required]
[PrimaryKey]
public int Groupid { get; set;} // this is a primary key
public int Ranking { get; set;}
public bool Isprimary { 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.

Data annotation in Servicestack References vs ForeignKey

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; }
}

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; }
}
}

Entity Framework 5 - Many to Many relationship between multiple table using same intermediate table

I am trying to implement the below scenario using Entity Framework 5, with code first approach.
Scenario: I have three tables say
Table1: { Id1, Title }
Table2: { Id2, Title }
Table3: { Id3, Title }
and single intermediate table storing many-to-many relationship between "Table1 &Table2" and "Table2 & Table3". Say,
TableIntermediate: { FK1, FK2 }
To specify the relation, On OnModelCreating(), I have specified two model builder:
modelBuilder.Entity<Table1>()
.HasMany(c => c.Table2s)
.WithMany(pc => pc.Table1s)
.Map(m =>
{
m.ToTable("TableIntermediate");
m.MapLeftKey("FK1");
m.MapRightKey("FK2");
});
modelBuilder.Entity<Table1>()
.HasMany(c => c.Table3s)
.WithMany(pc => pc.Table1s)
.Map(m =>
{
m.ToTable("TableIntermediate");
m.MapLeftKey("FK1");
m.MapRightKey("FK2");
});
Below are the entities defined:
public class Table1
{
public int Id1 {get; set;}
public string Title {get; set;}
public ICollection<Table2> Table2s { get; set; }
public ICollection<Table3> Table3s { get; set; }
}
public class Table2
{
public int Id2 {get; set;}
public string Title {get; set;}
public ICollection<Table1> Table1s { get; set; }
}
public class Table3
{
public int Id3 {get; set;}
public string Title {get; set;}
public ICollection<Table1> Table1s { get; set; }
}
The code compiles properly. But at runtime throwing the error:
{"Schema specified is not valid. Errors: \r\n(275,6) : error 0019: The EntitySet 'Table1Table2' with schema 'XXXX' and table 'TableIntermediate' was already defined. Each EntitySet must refer to a unique schema and table."}
As we are using the exiting database, we want to store both the relations into a single intermediate table. The only solution I found is to introduce a new mapping table. Please let me know if the scenario is possible without introducing the new mapping table.

ServiceStack OrmLite create table with [AutoIncrement] fail

I am using ServiceStack version="3.9.54" targetFramework="net40" with PostgreSQL.\
When i create table with
public class test
{
[AutoIncrement]
public int id { get; set; }
public string test_name { get; set; }
}
dbConn.CreateTable<test>(true);
CREATE TABLE test
(
id serial NOT NULL,
test_name text,
CONSTRAINT test_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE);
But when i create with
public class test
{
public string test_name { get; set; }
[AutoIncrement]
public int id { get; set; }
}
dbConn.CreateTable<test>(true);
Here is table on Postgres
CREATE TABLE test
(
test_name text NOT NULL,
id integer NOT NULL,
CONSTRAINT test_pkey PRIMARY KEY (test_name)
)
WITH (
OIDS=FALSE
);
What happen with my id columns. Is it bug ?
Thanks for your help
Tuan Hoang Anh
I think there are some conventions and case-sensitivity at play here. If you change id to Id it should work
public class test
{
public string test_name { get; set; }
[AutoIncrement]
public int Id { get; set; }
}
dbConn.CreateTable<test>(true);
OrmLite expects an 'Id' property to be present and to be the primary key. You can attribute a property with [PrimaryKey] if you don't want to use Id. However, in this case attributing id with [PrimaryKey] will attempt to create 2 primary keys since OrmLite can't find an Id field and (I think) defaults the first property it finds to be the primary key (can't find docs/proof to back this up, though)

Resources