ServiceStack ORMLite how to not serialize list - servicestack

I don't know how to store collection (Comments) in separate table.
By default comments are serialized and stored in SomeClass table as column Comments.
[{Id:0,CreateDate:2013-09-12T14:28:37.0456202+02:00,,SomeClassID:1,CommentText:"coment text",}]
Is there any way to save it in separate tables?
public class SomeClass {
[AutoIncrement]
public int Id { get; set; }
public string Title { get; set; }
List<Comment> comments = new List<Comment>();
public List<Comment> Comments {
get { return comments; }
set { comments = value; }
}
}
public class Comment {
[AutoIncrement]
public int Id { get; set; }
[References(typeof(SomeClass))]
public int SomeClassID { get; set; }
[StringLength(4000)]
public string CommentText { get; set; }
}

I don't think ORMLite supports serializing to multiple tables. 1 table = 1 class so the comments will be stored as a Blob field in the SomeClass table.
If you need to store them in separate tables you will have to save the comments separately and have a foreign key reference back to the id of the SomeClass table.

Related

Autquery not including nested result when using a response DTO

Let's say you have these models:
public class Blog
{
[PrimaryKey]
[AutoIncrement]
public int Id { get; set; }
public string Url { get; set; }
public string PrivateField { get; set; }
[Reference]
public List<BlogToBlogCategory> BlogToBlogCategories { get; set; }
}
public class BlogResponse
{
public int Id { get; set; }
public string Url { get; set; }
public List<BlogToBlogCategory> BlogToBlogCategories { get; set; }
}
And this request:
public class BlogsLookUpRequest : QueryDb<Blog, BlogResponse>
{
}
The return value will have BlogToBlogCategories as null, but this request:
public class BlogsLookUpRequest : QueryDb<Blog>
{
}
Will have BlogToBlogCategories populated. I can manually create the query response like so with custom implementation:
var q = _autoQuery.CreateQuery(request, Request.GetRequestParams(), base.Request);
var results = _autoQuery.Execute(request,q, base.Request);
return new QueryResponse<ResponseBlog>()
{
Results = results.Results.ConvertTo<List<ResponseBlog>>(),
Offset = request.Skip,
Total = results.Total
};
Then it will have the nested results. If I decorate the collection with [Reference] then it is trying to find foreign key on non-existant BlogResponse table.
Why are referenced results removed when specifying a return model with AutoQuery? Is there a way to mark it up so it works?
The POCO Reference Types is used to populate Data Models not adhoc Response DTOs.
In this case it's trying to resolve references on a non-existent table, you can specify which table the DTO maps to with [Alias] attribute, e.g:
[Alias(nameof(Blog))]
public class BlogResponse
{
public int Id { get; set; }
public string Url { get; set; }
public List<BlogToBlogCategory> BlogToBlogCategories { get; set; }
}

PATCH in ServiceStack

I am trying to patch a object with the following code.
public object Patch(EditBlog request)
{
using (var db = _db.Open())
{
try
{
request.DateUpdated = DateTime.Now;
Db.Update<Blog>(request, x => x.Id == request.Id);
return new BlogResponse { Blog = Blog = Db.Select<Blog>(X=>X.Id == request.Id).SingleOrDefault()};
}
catch (Exception e)
{
return HttpError.Conflict("Something went wrong");
}
}
}
In Postman, I am calling the function like this "api/blog/1?=Title=Test1&Summary=Test&UserId=1".
When debugging I can see that those values has been assigned to the request.
During the Update it throws: "Cannot update identity column 'Id'"
My model looks like this
public class Blog
{
[AutoIncrement]
public int Id { get; set; }
public IUserAuth User { get; set; }
[Required]
public int UserId { get; set; }
[Required]
public string Title { get; set; }
public string Summary { get; set; }
public string CompleteText { get; set; }
[Required]
public DateTime DateAdded { get; set; }
public DateTime DateUpdated { get; set; }
}
And the EditBlog DTO looks like this:
[Route("/api/blog/{id}", "PATCH")]
public class EditBlog : IReturn<BlogResponse>
{
public int Id { get; set; }
public IUserAuth User { get; set; }
public int UserId { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string CompleteText { get; set; }
public DateTime DateUpdated { get; set; }
}
The error message "Cannot update identity column 'Id'" does not exist anywhere in ServiceStack.OrmLite, it could be an error returned by the RDBMS when you're trying to update the Primary Key which OrmLite wouldn't do when updating a Model annotated with a Primary Key like your Blog class has with its annotated [AutoIncrement] Id Primary Key.
The error is within your Db.Up<T> method that's performing the update, which is not an OrmLite API, so it's likely your own custom extension method or an alternative library.
I would implement a PATCH Request in OrmLite with something like:
var blog = request.ConvertTo<Blog>();
blog.DateUpdated = DateTime.Now;
Db.UpdateNonDefaults(blog);
i.e. using OrmLite's UpdateNonDefaults API to only update non default fields and updating using the Blog Table POCO not the EditBlog Request DTO.
Also you should use the Single APIs when fetching a single record, e.g:
Blog = Db.SingleById<Blog>(request.Id)
or
Blog = Db.Single<Blog>(x => x.Id == request.Id)
Instead of:
Blog = Db.Select<Blog>(X=>X.Id == request.Id).SingleOrDefault()

Conversion failed,when using AutoQuery in ServiceStack

I have the following AutoQuery function.
[Route("/cars/search")]
public class SearchCars : QueryDb<Car, CarDto>
{
public List<int> EquipmentIds { get; set; }
public List<int> ManufacturerIds { get; set; }
public List<int> ColourIds { get; set; }
}
The function works, when I do the following:
Cars/Search?ColourIds=1&format=json
Cars/Search?ManufacturerIds=1&format=json
but when I try to use
Cars/Search?EquipmentIds=1&format=json
I get "Conversion failed when converting the varchar value '[1]' to data type int.".
The difference between these fields is that Car object can have multiple EquipmentIds, but only one ColourId and ManufacturerId.
public class Car
{
[AutoIncrement]
public int Id { get; set; }
public Colour Colour { get; set; }
[Required]
public int ColourId { get; set; }
public Manufacturer Manufacturer { get; set; }
[Required]
public int ManufacturerId { get; set; }
[Required]
public List<Equipment> Equipment { get; set; }
[Required]
public List<int> EquipmentId { get; set; }
}
Do I have to define for which attribute the different parameters should be assigned too?
AutoQuery works by constructing an RDBMS query based on implicit conventions which is used to construct an SQL query that runs on the RDBMS.
Complex Types in OrmLite data models are blobbed by default which means they can't be queried in the RDBMS with SQL, so you wont be able to query it with AutoQuery.
You could create a hybrid Custom AutoQuery Implementation where you can apply any custom logic to filter the results of the AutoQuery results, something like...
public class MyQueryServices : Service
{
public IAutoQueryDb AutoQuery { get; set; }
//Override with custom implementation
public object Any(SearchCars query)
{
var equipmentIds = query.EquipmentIds;
query.EquipmentIds = null;
var q = AutoQuery.CreateQuery(query, base.Request);
var response = AutoQuery.Execute(query, q);
if (equipmentIds != null)
response.Results.RemoveAll(x => x.EquipmentId...);
return response.
}
}

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.

I need a mix of table per hierarchy or type in entity framework

I have 3 entities and I want to use them for EF as POCO`s:
TimeTable is the base class for Period and LessonPlanner classes.
How can I use/map these 3 classes with EF 5.0 or higher?
I want to get 2 sql tables created: Period and LessonPlanner.
EF supports only Table per hierarchy or Table per type.
Either I get one table containing all properties as fields OR I get 3 separated tables.
I just want 2 tables whatever approach I have to take I do not care: Database/Model/Code first...
public class TimeTable
{
public int Id { get; set; }
public int LessonNumber { get; set; }
public string SchoolclassNumberForSunday { get; set; }
public string SchoolclassNumberForMonday { get; set; }
public string SchoolclassNumberForTuesday { get; set; }
public string SchoolclassNumberForWednesday { get; set; }
public string SchoolclassNumberForThursday { get; set; }
public string SchoolclassNumberForFriday { get; set; }
public string SchoolclassNumberForSaturday { get; set; }
}
public class Period : TimeTable
{
public enum WeekType
{
A,
AB,
}
}
public class LessonPlanner : TimeTable
{
public DateTime LessonDate { get; set; }
}
Using code first in Entity Framework 5, in the DbContext derived class, override OnModelCreating and add the following code. I've not tried it with your types but I've used a variant of this to create two classes for a three deep hierarchy.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Period>()
.Map<Period>(p => p.MapInheritedProperties())
.ToTable("Period");
modelBuilder.Entity<LessonPlanner>()
.Map<LessonPlanner>(lp => lp.MapInheritedProperties())
.ToTable("LessonPlanner");
}

Resources