Sqlite-net extensions relations always null - c#

I am trying to use the extension in MvvmCross 4. What I am trying to do is simple: I have two tables with a one to many relationship and and want to access this.
I have two classes, BusLine and BusLineGroup. Each BusLine has one Group as foreign key. What I do in code is run a simple LINQ-Query to get all Buslines:
var testQuery =
from busLine in this._connection.Table<BusLine>()
select busLine;
The query itself works, but if I check the fields of the returned objects, the Group is always null!. See below for the class and table definitions.
What am I doing wrong? Why is the group always null? Thanks for your help.
The classes in code:
public class BusLine
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey(typeof(BusLineGroup))]
public int BusLineGroup { get; set; }
[ManyToOne]
public BusLineGroup LineGroup { get; set; }
}
public class BusLineGroup
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Color { get; set; }
public string MainStations { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BusLine> BusLines { get; set; }
}
The two tables:
CREATE TABLE "BusLineGroup" (
`Id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`Name` TEXT NOT NULL,
`Color` TEXT NOT NULL,
`MainStations` TEXT NOT NULL
);
CREATE TABLE "BusLine" (
`Id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`Name` TEXT NOT NULL,
`BusLineGroup` INTEGER NOT NULL,
FOREIGN KEY(`BusLineGroup`) REFERENCES `BusLineGroup`(`Id`)
);
Installed Nuget-Packages:
MvvmCross.Plugin.SQLitePCL
SQLiteNetExtensions
Note: The MvvmCross package automatically includes SQLite.Net-PCL. So both of those two use the same PCL.

You are not using any SQLite-Net Extensions method there, you are using plain sqlite.net methods that know nothing about your relationships. You have to use the WithChildren methods to read and write relationships from database.
For example, your query can be replaced with this line:
var testQuery = this._connection.GetAllWithChildren<BusLine>();
That will also fetch first-level relationships from database.
I'd recommend you to take a look at the SQLite-Net Extensions documentation and the sample project for more examples.

Related

How to change class properties name generation in Entity Framework Code First from database

I have a database with a lot of tables, and table X has many foreign keys to table Y. When I use Entity Framework Code First to generate C# model corresponding to may database the class X has a lot of properties of type Y called Y, Y1, ... Yn. For example:
public virtual Author Author { get; set; }
public virtual Author Author1 { get; set; }
public virtual Author Author2 { get; set; }
And I want to have something like:
public virtual Author Writer { get; set; }
public virtual Author Supervisor { get; set; }
public virtual Author Reviewer { get; set; }
Coresponding to mai SQL table columns:
[WriterId] [int] NOT NULL,
[SupervisorId] [int] NOT NULL,
[ReviewerId] [int] NOT NULL,
I know that I can add partial classes to add extra properties like in below example:
public virtual Author AuthorWriter
{
get
{
return this.Author1;
}
set
{
this.Author1 = value;
}
}
but I would have to much code to write. So my question is if is there a way in Visual Studio 2013 to configure how virtual properties names are generated by Entity Framework?
I mention that I do not want to change the generation of C# model way because the database is larger and I do not have access to modify its structure, moreover if the database is changed I should regenerate my C# model.
Thanks in advance

SQLite and SQLite-Extensions can not perform OneToOne relationsip

I'm using SQLite-Net-Extensions. I'm attempting to define a OneToOne relationship so that when my Accounts model is loaded it will also include the Campaign so that I can access the campaign name.
The problem is Accounts.Campaign is always null. I have data in both tables.
Here's my tables in SQLite:
CREATE TABLE `campaigns` (
`Id` INTEGER PRIMARY KEY AUTOINCREMENT,
`Name` TEXT UNIQUE
);
and
CREATE TABLE `accounts` (
`Id` INTEGER PRIMARY KEY AUTOINCREMENT,
`CampaignId` INTEGER,
`MobileNumber` TEXT UNIQUE,
`Password` TEXT
);
Below are my models:
namespace SMA.Models
{
[SQLite.Table("accounts")]
class Accounts
{
[PrimaryKey, AutoIncrement]
public Int32 Id { get; set; }
[ForeignKey(typeof(Campaigns))]
public Int32 CampaignId { get; set; }
[MaxLength(11)]
public string MobileNumber { get; set; }
[MaxLength(50)]
public string Password { get; set; }
[OneToOne("Id")]
public Campaigns Campaign { get; set; }
}
}
and
namespace SMA.Models
{
[Table("campaigns")]
class Campaigns
{
[PrimaryKey, AutoIncrement]
public Int32 Id { get; set; }
[MaxLength(50)]
public string Name { get; set; }
}
}
I run the following code to fetch all of the accounts:
var accounts = this.db.Table<SMA.Models.Accounts>().ToList();
Also tried ...
var accounts = this.db.Query<Account>("SELECT * FROM accounts");
And ...
var accounts = this.db.Query<Account>("SELECT * FROM accounts JOIN campaigns ON accounts.CampaignID = campaigns.ID");
When I inspect accounts the account data is there, but Accounts.Campaign is null. I can't seem to see what I'm doing wrong.
Try using SQLite-Net Extension read methods instead of plain sqlite.net Query or Table. For example:
var accounts = this.db.GetAllWithChildren<Account>();
Also, make sure that you're either setting foreign keys manually or using SQLite-Net Extensions to write relationships to database.
To make SQLite-Net Extensions methods available make sure that you're importing SQLiteNetExtensions.Extensions namespace:
import SQLiteNetExtensions.Extensions;
If they're still not available, make sure that there are no duplicated sqlite.net libraries in your packages.

MVC creating a list as a model property not being added as foreign key to DB with code first entity framework

I am starting a code first EF MVC project. Below is the code for a Message model that I am creating. Is it possible to create a tags property that is a list of tags (another model I created) like I am attempting below?
public class Message
{
public int Id { get; set; }
public string Text { get; set; }
public byte[] Attachment { get; set; }
[Required]
public MessageBoard MessageBoard { get; set; }
[Required]
public virtual List<Tag> Tags { get; set; }
}
After attempting the update-database -verbose command, I see that it does not add a Tags class to my database. The console shows this db command for messages:
CREATE TABLE [dbo].[Messages] (
[Id] [int] NOT NULL IDENTITY,
[Text] [nvarchar](max),
[Attachment] [varbinary](max),
[MessageBoard_Id] [int] NOT NULL,
CONSTRAINT [PK_dbo.Messages] PRIMARY KEY ([Id])
)
How can I create this foreign key relationship between messages and tags?
I assume that you one Many to Many relationship to reuse existing tags.
First of all you have to add to your Tag class a reference to Message
public virtual List<Message> Messages { get; set; };
Then in your model configuration class you have to set the relation many to many, with the following code :
modelBuilder.Entity<Message>()
.HasMany<Tag>(m => m.Tags)
.WithMany(t => t.Messages)
.Map(mt =>
{
mt.MapLeftKey("MessageID");
mt.MapRightKey("TagId");
mt.ToTable("MessagesTag"); //Name of table many to many
});
And don't forget to add class Tag in your DBContext too.
public DbSet<Tag> Tag { get; set; }

Database-first approach in Entity Framework without auto generated code

I wonder, if there is any way ,
to use Database-first approach with manually generated classes (models) in advance(just like Code-first approach),
but without using auto-generated code which Entity Framework creates using Database-first approach?
I have 3 Classes(first two of them Student and Courses have many to many relationship), which represents models:
First one is Student:
public class Student
{
public int StudentID { get; set;}
public string Name { get; set;}
public DateTime BirthDate { get; set;}
public ICollection<StudentToCourse> StudentToCourses { get; set; }
public Student()
{
StudentToCourses = new List<StudentToCourse>();
}
}
Then Course:
public class Course
{
public int CourseID { get; set; }
public string CourseName { get; set; }
public ICollection<StudentToCourse> StudentToCourses { get; set; }
public Course()
{
StudentToCourses = new List<StudentToCourse>();
}
}
And Relation/Intermediate Class with additional properties StudentToCourse:
public class StudentToCourse
{
[Key, Column(Order = 0)]
public int StudentID { get; set; }
[Key, Column(Order = 1)]
public int CourseID { get; set; }
[Key, Column(Order = 2)]
public DateTime Date { get; set; }
public virtual Student Student { get; set; }
public virtual Course Course { get; set; }
//public ICollection<Student> Students { get; set; }
//public ICollection<Course> Courses { get; set; }
public int Grade { get; set; }
}
Also, i created Database, using LocalDb feature in VS 2013
I have 3 Tables:
Courses:
CREATE TABLE [dbo].[Courses]
(
[CourseID] INT NOT NULL PRIMARY KEY IDENTITY,
[CourseName] NVARCHAR(100) NOT NULL,
)
Students:
CREATE TABLE [dbo].[Students]
(
[StudentID] INT NOT NULL PRIMARY KEY IDENTITY,
[Name] NVARCHAR(50) NOT NULL,
[BirthDate] DATETIME NOT NULL,
)
Relation Table StudentsToCourses:
CREATE TABLE [dbo].[StudentsToCourses]
(
[StudentID] INT REFERENCES Students(StudentID) NOT NULL,
[CourseID] INT REFERENCES Courses(CourseID) NOT NULL,
[Date] DATETIME NOT NULL,
[Grade] INT NOT NULL,
PRIMARY KEY (StudentID, CourseID, Date)
)
Unfortunately, i have no luck with this approach, i do get students' data but i don't receive data from relational table and i can't receive all related grades per student.
I searched for related topics in google and in stackoverflow , but all those topics weren't helpful for me, although the example above i found in this topic.
As I suspected, the problem is not whether or not you can have a database and a class model independently. Of course you can! All these generation tools and migration stuff only serve one goal: making life easier, help you keeping both models in sync. But you can do that job yourself just as well. The end result is always: two models that – at runtime – don't interact with each other whatsoever. (Don't interact? No, not as such. There must be a middleman, an ORM, to connect both worlds.)
The reason why you don't get data is because lazy loading does not occur. Your statement is
var listOfGrades = _context.Students.Where(s => s.Name.StartsWith("J"))
.FirstOrDefault().StudentToCourses;
This requires lazy loading, because the FirstOrDefault() statement executes the first part of the query. It renders a Student of which subsequently the StudentToCourses are accessed. But these don't load because the collection is not virtual. It should be
public virtual ICollection<StudentToCourse> StudentToCourses { get; set; }
This enables EF to override the collection in a dynamic proxy object that is capable of lazy loading.
But of course is is more efficient to get the collection in one statement, for example:
var listOfGrades = _context.Students.Include(s => s.StudentToCourses)
.Where(s => s.Name.StartsWith("J"))
.FirstOrDefault().StudentToCourses;
Yes, you can. You just need a context with no initialization strategy (so it doesn't try to create or migrate your existing database):
public class ExistingDatabaseContext : DbContext
{
public ExistingDatabaseContext()
: base("ExistingDatabaseConnectionStringName")
{
Database.SetInitializer<ExistingDatabaseContext>(null);
}
// DbSets here for your "code-first" classes that represent existing database tables
}
Just bear in mind that this context will not be capable of doing migrations or any other form of initialization, so if you have actual true code-first tables in there as well, you'll need a separate context to manage those.

I don´t get why my class is mapped as complex type

I want to display information from a user-defined function in ASP.NET MVC 4 Razor. The function in the database looks like this:
CREATE FUNCTION dbo.udf_GetReportsByController(#controller_account VARCHAR(128))
RETURNS #retReports table (
ID INTEGER IDENTITY PRIMARY KEY,
ProviderID VARCHAR(50) NOT NULL ,
VertragID INTEGER NOT NULL,
Leistungszeitraum_von DATE NOT NULL,
Leistungszeitraum_bis DATE NOT NULL,
ReportklasseID VARCHAR(50) NOT NULL,
Version INTEGER NOT NULL,
Status VARCHAR(64)
)
AS
BEGIN
//Do some stuff and insert in the ret-table
RETURN;
END;
GO
Entity Framework mapped this in this class:
public partial class udf_GetReportsByController_Result
{
[Column("ID")]
public int ID { get; set; }
[Column("ProviderID")]
public string ProviderID { get; set; }
[Column("VertragID")]
public int VertragID { get; set; }
[Column("Leistungszeitraum_von")]
public System.DateTime Leistungszeitraum_von { get; set; }
[Column("Leistungszeitraum_bis")]
public System.DateTime Leistungszeitraum_bis { get; set; }
[Column("ReportklasseID")]
public string ReportklasseID { get; set; }
[Column("Version")]
public int Version { get; set; }
[Column("Status")]
public string Status { get; set; }
}
When I want to do some DbSet-Methods in my Controller, I get an Error message, that my model class is mapped as complex Type. I read that a complex type has no primary key, but I defined one in my function, and I need to address an element by it´s ID. How can I specify the primary key in this ret-Table?
When you do something like
context.Set<udf_GetReportsByController_Result>()
Entity Framework will look for a table that is mapped against the result type. However, this table doesn't exist. The function does return a table, but this is a table variable, not a table that's part of the database schema. Only entity types are mapped against schema tables.
You can only get udf_GetReportsByController_Result objects by calling the imported function:
var results = context.udf_GetReportsByController(accountNo);

Categories

Resources