Using schema names with SQL Server & ServiceStack.OrmLite - sql-server

Anyone know how to apply the correct Alias attribute to query tables with schema names?
I have a table called accounts.register. I've tried using [Alias("accounts.register")] as the class decorator attribute for Register class but this doesn't work.
If I change the schema to dbo then I can remove the alias and everything works. Unfortunately I have a legacy system with many schemas so I need this to work.

OK I figured it out. Along with the Alias attribute is the Schema attribute. The former is in the ServiceStack.DataAnnotations namespace but the latter is in the ServiceStack.OrmLite namespace. Here's an example to map fields field1 & field2 to/from myschema.mytable:
using System;
using ServiceStack.OrmLite;
using ServiceStack.DataAnnotations;
[Schema("myschema")]
[Alias("mytable")]
public class MyEntity
{
[PrimaryKey]
[AutoIncrement]
public long Id { get; set; }
[Alias("field1")]
public string SomeField1 { get; set; }
[Alias("field1")]
public string SomeField2 { get; set; }
}

Related

Another efcore violation of primary key constraint reference table problem

Assume I've read and googled, and I still don't know what I'm doing incorrectly. Whenever I try to execute
_dbContext.Set<T>().Add(aMediaObjectWithAssociatedProvider);
_dbContext.SaveChanges();
I get the dreaded efcore violation of primary key constraint reference table
I have a class as such:
public class Media : BaseModel
{
public virtual string Title { get; set; }
public virtual string? Description { get; set; }
public virtual string Source { get; set; }
public virtual Guid? MediaTypeId { get; set; }
public virtual Guid? ProviderId { get; set; }
public virtual DateTime? StartDate { get; set; }
public virtual DateTime? EndDate { get; set; }
public virtual Provider? Provider { get; set; }
}
The BaseModel class is
public abstract class BaseModel : IBaseModel
{
public virtual Guid Id { get; set; }
}
The Provider class is as such:
public class Provider : BaseModel
{
public virtual string Name { get; set; }
public virtual string? ApiUsername { get; set; }
public virtual string? ConfigurationSection{ get; set; }
}
My DBContext has the following:
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Media>().HasKey(x => x.Id);
mb.Entity<Media>().HasOne(p => p.Provider).WithOne().HasForeignKey<Media>(x => x.ProviderId);
}
The code for inserting a new object is as follows:
public T Insert(T oneObject)
{
try
{
// Ensure the entity has an ID
if (oneObject.Id == Guid.Empty)
{
oneObject.Id = Guid.NewGuid();
}
_dbContext.Set<T>().Add(oneObject);
_dbContext.SaveChanges();
}
catch (Exception error)
{
_logger.LogError(error.Message, error);
}
return oneObject;
}
Assume that providers are static, in a sense that they already exist in their table, and I don't want to add new providers when I save media... Media just needs to have a provider.
I know exactly what is happening (the model, after travelling through json back through the api to the server is losing context, but I'm also trying to build a repository type of system where I don't have to build complex save logic for every object. (hence why i'm hand wringing over adding code that loads existing providers).
This problem specifically began rearing its head when I was saving new Media objects into the database with existing Providers. I am still mulling over how to look up children dynamically, but i'm not quite there yet.
I've been at this for so long, i'm about ready to give up on efcore relations and just rebuild the models as single objects, and handle all of the manipulation in javascript. And I don't like this idea.
I know for a fact that there will be questions for more code, but please let me know what. Again, I'm just stepping into .net core / ef core so this code-first is a little confusing for me. Thanks
You may have 2 options to try. Do backup your whole project and database beforehand. Clone your database to another database name. Try these either one option using new cloned database for testing.
No.1
Set "newid()" without quotes in your ID's default value in sql server. So you don't need to use Guid.NewGuid() in code every insert. newid() will auto generate GUID.
No. 2
How about removing primary key from ID (GUID) and then creating new column "UID" (running number) and set UID (running number) as primary key and enable its identity? You need to change all other tables too. And re-link UID each other if you use relationship. This way, your UID will not have existing number when insert.

Entity framework, Data annotations [DatabaseGenerated(DatabaseGeneratedOption.Identity)] and sequential GUID

I'm trying to use the entity framework to communicate with my existing DB. This is thus DB first. Using sql server and c#. The problem is that I would like to use a sequential GUID, generated by the database.
Each time I run the code, my controller pastes the GUID assigned to lutRoughagePhysicalSiloId to the DB (most of the time lutRoughagePhysicalSiloId is just an empty GUID (000..) since I don't fill it). As far as I can see, this should not be happening since I use [DatabaseGenerated(DatabaseGeneratedOption.Identity)].
Any Ideas?
SQL code
CREATE TABLE [dbo].[lutRoughagePhysicalSiloType]
(
[RoughagePhysicalSiloTypeId] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY UNIQUE DEFAULT NEWSEQUENTIALID(),
[PhysicalSiloTypeName] NVARCHAR(50) NOT NULL UNIQUE
)
(Notice the Default value newsequentialId() that gets generated as default by sql server)
Automatic created modelview (DB first):
namespace guiIlvoDairyCowBarn.Models
{
using System;
using System.Collections.Generic;
public partial class lutConcentratePhysicalSiloType
{
public lutConcentratePhysicalSiloType()
{
this.lutConcentratePhysicalSiloes = new HashSet<lutConcentratePhysicalSilo>();
}
public System.Guid ConcentratePhysicalSiloTypeId { get; set; }
public string PhysicalSiloTypeName { get; set; }
public virtual ICollection<lutConcentratePhysicalSilo> lutConcentratePhysicalSiloes { get; set; }
}
}
Buddy class
namespace guiIlvoDairyCowBarn.Models
{
[MetadataType(typeof(lutRoughagePhysicalSiloMD))]
public partial class lutRoughagePhysicalSiloType
{
public class lutRoughagePhysicalSiloMD
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public System.Guid RoughagePhysicalSiloTypeId { get; set; }
[Required, DisplayName("Physical silo type")]
public string PhysicalSiloTypeName { get; set; }
public virtual ICollection<lutRoughagePhysicalSilo> lutRoughagePhysicalSiloes { get; set; }
}
}
}
what is a Buddy class suppose to mean?
Using both [Key] and the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] should work and ignore any user provided value. After saving to the DB the property should have the DB generated Guid.
Your class lutConcentratePhysicalSiloType has no EF data annotations and if saved would take the values you provided. NewSequentialId() is a default and without any EF data annotations the DB row will get whatever the value you specify in the C# class.

Creating seed model from data already in DB

Is there a way to convert data in an existing database into objects that can easily be put into a seed method?
Essentially I'd like to let some people add lines to my DB via a form and then convert that into an object that I can re-seed the DB anytime I need to make changes.
The database itself is created via code-first using the following model:
public class Combo
{
public int Id { get; set; }
public string MainPrefix { get; set; }
public string MainDescriptor { get; set; }
public string MainDish { get; set; }
public string Connector { get; set; }
public string SecondaryDescriptor { get; set; }
public string SecondaryDish { get; set; }
}
High level untested idea:
Create a new T4 template which will use either your context or direct SQL to query database and generate either C# static class with method (which will return collection of object created from database data) or SQL insert commands. Depending on what you choose you will either call static method in Seed to get all entities you want to insert or simply load the created SQL script and execute it.
You can also do the same without T4 by using Code Dom (if you want to generate C# code) and creating a new custom tool for visual studio.
These features can be part of your project or the result (C# code) can be compiled in separate external assembly.

RIA Services SP2 Function Complex type not visible in Object Context

I am struggling with returning a complex type from my services layer. It doesnt seem to be accessible from my object context.
This is the query in the service layer. All compiling fine.
public IQueryable<USP_GetPostsByThreadID_Result> uspGetPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}
When I try and call it from my client, the ForumContext is not seeing it. I checked the client generated file and nothing similar is being generated. Help!!!
The name of your method may not meet the expected convention for queries. Try one or both of the following:
Add the [Query] attribute
Rename the method to GetUspPostsByThreadID
Result:
[System.ServiceModel.DomainServices.Server.Query]
public IQueryable<USP_GetPostsByThreadID_Result> GetUspPostsByThreadID(int ThreadID)
{
return this.ObjectContext.USP_GetPostsByThreadID(ThreadID).AsQueryable();
}
Its very common to have a stored procedure returning data from multiple tables. The return type doesn't fit well under any of the Entity Types(Tables). Therefore if we define Complex Type as the return collection of objects from Stored Procedure invocation, it becomes quite a powerful tool for the developer.
Following these steps I have achieved successfully the configuration of complex type on a sample AdventureWorks database.
1. Refer the picture and ensure the Stored procedure and function import is done.
2. Add the Domain Service name it as AdventureDomainService.
3. Now its time to define the tell the RIA services framework to identify my Complex Type as Entity Type. To be able to do this, we need to identify a [Key] DataAnnotation. Entity types provide data structure to the application's data model and by design, each entity type is required to define a unique entity key. We can define key on one property or a set of properties in metadata class file AdventureDomainService.metadata.cs
First define the class then add MetadatatypeAttribute like :
[MetadataTypeAttribute(typeof(CTEmployeeManagers.CTEmployeeManagersMetadata))]
public partial class CTEmployeeManagers
{
internal sealed class CTEmployeeManagersMetadata
{
private CTEmployeeManagersMetadata() { }
[Key]
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int ManagerID { get; set; }
public string ManagerFirstName { get; set; }
public string ManagerLastName { get; set; }
}
}
Define the Domain service method to return the collection of objects/entities for populating the Silverlight Grid or any other data consuming controls.
public IQueryable<CTEmployeeManagers> GetEmployeeManagers(int empId)
{
return this.ObjectContext.GetEmployeeManagers(empId).AsQueryable();
}
We define IQueryable if we are to fetch the records from datasources like SQL, whereas we define IEnumerable if we are to fetch the records from in memory collections,dictionaty,arrays.lists, etc.
Compile the server side to generate the client proxy.
In the Silverlight side open the MainPage.xaml or wherever the datagrid is put, then add following namespaces :
using System.ServiceModel.DomainServices.Client;
using SLBusinessApplication.Web;
using SLBusinessApplication.Web.Services;
..
Load the data and display:
public partial class MyPage : Page
{
AdventureDomainContext ctx = new AdventureDomainContext();
public MyPage()
{
InitializeComponent();
LoadOperation loadOp = this.ctx.Load(this.ctx.GetEmployeeManagersQuery(29));
myGrid.ItemsSource = loadOp.Entities;
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
}
That is all that is needed to do.
It has to be part of an entity. Complex types cannot be returned by themselves

How can I stop Fluent NHibernate from creating foreign keys

I got a polymorphic relationship like the following example:
public class A
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}
Class B & C contining a List of A's:
public class B/C
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<A> As { get; set; }
public virtual SomeParent Parent { get; set; }
}
My goal are queries like
session.Linq<B>().Where(x => x.Parent == someParent && x.As.Contains(someA));
Currently I configured a Many-To-Many relation between B => A and C => A using a shared link table because I want to have all my links in one table.
In this examle NH shema export creates 4 tables, A, B, C and ChildToA.
HasManyToMany(x => x.As)
.AsBag()
.Table("XX_ChildToA")
.ParentKeyColumn("Child_ID")
.ChildKeyColumn("A_ID")
.Cascade.All()
This works fine as long as you use only one the child types because shema export generates a foreign key restricting the "Child_ID" to IDs of whatever table it hits first while exporting (B in this case).
var b = session.Get<B>(id);
b.As.Add(someA);
tx.Commit(); // works fine
var c = session.Get<C>(id);
c.As.Add(someA);
tx.Commit(); // crashes because of FK constraint
Can I stop FluentNHibernate from creating this FK? While I searched google for this problem I noticed HBM samples with foreign-key="no" attributes in many-to-one relationships. So NHibernate should be able to solve this, right? However I would like to keep my fluent mappings because I can create a generic base mapping class for all my child types this way and currently all our mappings are FNH mappings.
This should do it:
HasManyToMany(x => x.As)
.ForeignKeyConstraintNames("no", "no");
I'm not entirely familiar with FluentNHibernate, but I'm assuming you could set this custom attribute on your mapping for the collection using something like:
.SetAttribute("foreign-key", "no")

Resources