Allow NULL Foreign Keys with SQLite-net-extensions - sqlite

I'd like to know if I can, with a SQLite database and SQLite-Net Exensions, add 2 foreign keys to the same table with, each time, one of the foreign keys empty.
My structure is the following:
[Table("Picture")]
public class Picture
{
[PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey(typeof(Contact))] // => Allow Null ?
public string TokenContact { get; set; }
[ForeignKey(typeof(Profile))] // Allow Null ?
public string TokenProfile { get; set; }
}
[Table("Contact")]
public class Contact
{
[PrimaryKey]
public string Token {get;set;}
[OneToMany]
public ObservableCollection<Picture> CollectionPicture {get; set;}
}
[Table("Profile")]
public class Profile:Contact
{
// Some other properties...
}
Thanks for your advices !

Related

Add a column to a many to many relation table code first entity framework

I have 2 classes which have a many to many relation.
public class Document
{
public int Id { get; set; }
public string Name { get; set; }
public bool AvailableOffline { get; set; }
public string URL { get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
}
public class Profile
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
On each profile I wish to have a SortOrder field for each document. So I made the joined table explicit in another class
public class ProfileDocuments
{
[Key, Column(Order = 0)]
public int DocumentId { get; set; }
[Key, Column(Order = 1)]
public int ProfileId { get; set; }
public int SortOrder { get; set; }
[ForeignKey("DocumentId")]
public virtual Document Document { get; set; }
[ForeignKey("ProfileId")]
public virtual Profile Profile { get; set; }
}
But when I update the database the table for this last class will not have a column for SortOrder. It only holds the 2 foreign keys. How can I tell EF to generate this table with my column?
When a junction table in a many-to-many association should contain more information than just the two foreign keys, it's no longer possible to map the association as a 'pure' many-to-many (with hidden junction class).
You need an explicit class in the class model to address the extra information (as you already found out), but this also changes the association into 1-n-1:
class Document
{
...
public virtual ICollection<ProfileDocument> ProfileDocuments { get; set; }
}
class Profile
{
...
public virtual ICollection<ProfileDocument> ProfileDocuments { get; set; }
}

Entity Framework Code First Foreign Key Columnname inheritence

Entity Framework code first (v6) creates a columnname in the database that I don't like. In tablename SharepointMappings it adds columnname: 'SharepointDestination_DestinationId' (foreign key).
It also generates a columnname SharepointDestinationId.
I would like to have 1 column, a foreign key, with the name 'SharepointDestinationId'.
My model looks like this:
public class Destination
{
public int DestinationId { get; set; }
}
public class SharepointDestination : Destination
{
public string UserName { get; set; }
public string Password { get; set; }
public string Domain { get; set; }
public string SiteUrl { get; set; }
public string DocumentLibraryName { get; set; }
public List<SharepointMapping> Mappings { get; set; }
}
public class SharepointMapping
{
public int SharepointMappingId { get; set; }
public string SourceFieldName { get; set; }
public string DestinationFieldName { get; set; }
//[ForeignKey("SharepointDestination")]
public int SharepointDestinationId { get; set; }
//[ForeignKey("SharepointDestinationId")]
public virtual SharepointDestination SharepointDestination { get; set; }
}
//.....
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// To use TPT inheritence
modelBuilder.Entity<SharepointDestination>().ToTable("SharepointDestinations");
//modelBuilder.Entity<SharepointMapping>()
// .HasRequired(m => m.SharepointDestination)
// .WithMany(d => d.Mappings)
// .HasForeignKey(m => m.SharepointDestinationId)
// .WillCascadeOnDelete(true);
}
It doesn't matter if i leave or add the attribute ForeignKey and it also doesn't matter if i make properties virtual or not. Completely deleting both properties on SharepointMapping or giving them a complete other name has no consequences.
I think this has something to do with the inheritence structure. Because it's 'only' a 1-n mapping.
How should I configure EF to have only 1 column with the name 'SharepointDestinationId' which should be a foreign key? (and also have the navigation property and DestinationId property on the SharepointMapping class)
Since the key of SharepointDestination is DestinationId, EF can't automatically figure it out. You could go with the annotation:
[ForeignKey("DestinationId")]
public virtual SharepointDestination SharepointDestination { get; set; }
and remove this:
[ForeignKey("SharepointDestination")]
public int SharepointDestinationId { get; set; }
The fluent should work as well if you comment out the annotation:
modelBuilder.Entity<SharepointMapping>()
.HasRequired(m => m.SharepointDestination)
.WithMany(d => d.Mappings)
.HasForeignKey(m => m.DestinationId)
.WillCascadeOnDelete(true);
The ForeignKey attribute is expecting a property name, not a table column name.
Really, you should be able to do this without any attributes.
The following should work:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Parent Parent { get; set; }
public int ParentId { get; set; }
}

cannot share table no matching primary key

The entity types 'Profile' and 'Country' cannot share table 'Countries' because they are not in the same type hierarchy or do not have a valid one to one foreign key relationship with matching primary keys between them.
try removing
public int? CountryID { get; set; }
from UserProfile so it looks like this:
public class UserProfile
{
[Key]
public int UserID { get; set; }
public virtual Country Country { get; set; }
}
public class Country
{
public Country()
{
Profiles = new HashSet<UserProfile>();
}
[Key]
public int CountryID { get; set; }
public ICollection<UserProfile> Profiles { get; set; }
}
another thing : you had ICollection<Profile> instead of ICollection<UserProfile>

Problems when using EF Reverse POCO Generator generated models

I'm using asp.net default membership provider to create a website.
I used 'EF Reverse POCO Generator' and got some csharp code of build-in membership tables, I removed some classes and kept only Applications, Memberships, Profiles, Roles and Users.
The problem is I cannot use them because of exceptions throwing when the database is initialized.
The first exception I encountered is complaining missing the primary key, I added [Key] annotation to the primary field, problem solved.
Then I got the second error seems complaining missing foreign keys:
Unable to determine the principal end of an association between the types 'GoHome.Models.Memberships' and 'GoHome.Models.Users'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Looks like can be solved by adding [ForeignKey], but after that I still got the third one, which I cannot find a solution in Google:
*Introducing FOREIGN KEY constraint 'FK_dbo.RolesUsers_dbo.Users_Users_UserId' on table 'RolesUsers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.*
Quite odd, as looks to me there is no table called 'RolesUsers' at all.
I only added two [ForeignKey] in Memberships and Profiles respectively, which resulted in the third error. Here is the code:
// Memberships
public class Memberships
{
//[ForeignKey("Applications")]
public Guid ApplicationId { get; set; } // ApplicationId
[Key]
[ForeignKey("Users")]
public Guid UserId { get; set; } // UserId (Primary key)
public string Password { get; set; } // Password
public int PasswordFormat { get; set; } // PasswordFormat
public string PasswordSalt { get; set; } // PasswordSalt
public string Email { get; set; } // Email
public string PasswordQuestion { get; set; } // PasswordQuestion
public string PasswordAnswer { get; set; } // PasswordAnswer
public bool IsApproved { get; set; } // IsApproved
public bool IsLockedOut { get; set; } // IsLockedOut
public DateTime CreateDate { get; set; } // CreateDate
public DateTime LastLoginDate { get; set; } // LastLoginDate
public DateTime LastPasswordChangedDate { get; set; } // LastPasswordChangedDate
public DateTime LastLockoutDate { get; set; } // LastLockoutDate
public int FailedPasswordAttemptCount { get; set; } // FailedPasswordAttemptCount
public DateTime FailedPasswordAttemptWindowStart { get; set; } // FailedPasswordAttemptWindowStart
public int FailedPasswordAnswerAttemptCount { get; set; } // FailedPasswordAnswerAttemptCount
public DateTime FailedPasswordAnswerAttemptWindowsStart { get; set; } // FailedPasswordAnswerAttemptWindowsStart
public string Comment { get; set; } // Comment
// Foreign keys
public virtual Applications Applications { get; set; } // MembershipApplication
public virtual Users Users { get; set; } // MembershipUser
}
// Profiles
public class Profiles
{
[Key]
[ForeignKey("Users")]
public Guid UserId { get; set; } // UserId (Primary key)
public string PropertyNames { get; set; } // PropertyNames
public string PropertyValueStrings { get; set; } // PropertyValueStrings
public byte[] PropertyValueBinary { get; set; } // PropertyValueBinary
public DateTime LastUpdatedDate { get; set; } // LastUpdatedDate
// Foreign keys
public virtual Users Users { get; set; } // UserProfile
}

Code first one to one foreign key

I have two model class, where I want to make one-to-one relation. When I make migration, I get an error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint
"FK_dbo.Uzytkownik_dbo.UserProfile_UserId". The conflict occurred in
database "db_wydarzenia", table "dbo.UserProfile", column 'UserId'.
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
[Table("Uzytkownik")]
public class Uzytkownik
{
[Key]
public int UzytkownikID { get; set; }
public int UserId { get; set; }
public string Imie { get; set; }
public string Nazwisko { get; set; }
public string Telefon { get; set; }
public string Email { get; set; }
[ForeignKey("UserId")]
public UserProfile UserProfile { get; set; }
}
EDIT:
Problem solved :)
I remove all data from uzytkownik table and it's go.
If you want one-to-one - you cannot have both the primary-key and the foreign-key specified. One-to-one is modeled via primary-keys (pk == pk), otherwise it becomes 'multiplicity' (and just typical one-to-many).
To get what you want just remove your other PK - and user UserId as both primary and fk...
[Table("Uzytkownik")]
public class Uzytkownik
{
// [Key] public int UzytkownikID { get; set; }
[Key]
public int UserId { get; set; }
[ForeignKey("UserId")]
public UserProfile UserProfile { get; set; }
}

Resources