I have the following DbContext:
namespace Tasks.Models
{
public class TaskDBInitializer : DropCreateDatabaseIfModelChanges<TasksContext>
{
protected override void Seed(TasksContext context)
{
var projects = new List<Projects>
{
new Projects{ Title="proTitle", Describe="proDescribe" },
};
projects.ForEach(p => context.Projects.Add(p));
context.SaveChanges();
base.Seed(context);;
}
}
public class TasksContext : DbContext
{
public TasksContext() : base("name=TaskDB")
{
Database.SetInitializer(new TaskDBInitializer());
}
public DbSet<Task> Task { get; set; }
public DbSet<Projects> Projects { set; get; }
}
}
I now want to add another model but don't want to lose data that exists within the current database.
How can I add a model to my DbContext without losing data?
Instead of using DropCreateDatabaseIfModelChanges<TContext> as your IDatabaseInitializer<TContext> use MigrateDatabaseToLatestVersion<TContext,TMigrationsConfiguration> which will determine changes within your DbContext then update your existing database to be compatible.
Here is an example of how to implement the MigrateDatabaseToLatestVersion initializer:
namespace Tasks.Models
{
public sealed class TaskDBConfiguration : DbMigrationsConfiguration<TasksContext>
{
public TaskDBConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = false;
}
protected override void Seed(TasksContext context)
{
var projects = new List<Projects>
{
new Projects { Title = "proTitle", Describe = "proDescribe" },
};
projects.ForEach(p => context.Projects.Add(p));
context.SaveChanges();
base.Seed(context);
}
}
public class TasksContext : DbContext
{
public TasksContext() : base("name=TaskDB")
{
Database.SetInitializer<TasksContext>(
new MigrateDatabaseToLatestVersion<TasksContext, TaskDBConfiguration>()
);
}
public DbSet<Task> Task { get; set; }
public DbSet<Projects> Projects { set; get; }
}
}
Related
App: Blazor Server .NET 5
Using Entity Framework Core
DB; Azure SQL DB
All Ok except for if I refresh the browser, the Helper properties returned by GetActivitys() are null.
Does the Helper property in Activity need a tag?
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Activity> Activitys { get; set; }
public DbSet<Helper> Helpers { get; set; }
}
public class DataAccessService : IDataAccessService
{
private readonly ApplicationDbContext _context;
public DataAccessService(ApplicationDbContext context)
{
_context = context;
}
public async Task<List<Activity>> GetActivitys()
{
var list = await _context.Activitys.ToListAsync<Activity>();
return list;
}
}
public class Activity
{
[Key]
[Column("Id")]
[JsonPropertyName("Id")]
public int Id { get; set; }
[Column("Task")]
[Required]
[JsonPropertyName("Task")]
public string Task { get; set; }
[Column("Helper")]
[JsonPropertyName("Helper")]
public Helper Helper { get; set; }
}
public class Helper
{
[Key]
[Column("Id")]
[JsonPropertyName("Id")]
public int Id { get; set; }
[Column("Name")]
[Required]
[JsonPropertyName("Name")
}
If you want to include navigational properties after materializing your query via .ToListAsync(), you must add a chained method .Include(activity => activity.Helper) before materialization.
I'm working on my first WPF MVVM application. I created a database and wrote queries to fetch album names and song names. Now I want to fill a list in my View with the album names and a second list with corresponding songs. I'm new to c# and WPF. I'd like to know how a view model would like for my controller would look like.
My controller:
public class BandManagerController
{
private bandkramEntities _context;
public BandManagerController()
{
_context = new bandkramEntities();
}
public List<AlbumData> GetAlbumList()
{
return _context.albums
.Select(a => new AlbumData
{
AlbumID = a.AlbumID,
AlbumName = a.AlbumName,
})
.ToList();
}
public List<SongData> GetSongList(int albumID)
{
return _context.songs
.Where(s => s.AlbumID == albumID)
.Select(s => new SongData
{
SongID = s.SongID,
SongName = s.SongName
})
.ToList();
}
}
I created a helper class with the NotifyOfPropertyChange class and a song and album data class:
AlbumData.cs
public class AlbumData
{
public string AlbumName { get; set; }
public int AlbumID { get; set; }
}
SongData.cs
public class SongData
{
public string SongName { get; set; }
public int SongID { get; set; }
}
For a better overview I want to split my Viewmodel into 4 main parts.
SongViewModel.cs
public class SongViewModel : NotifyOfPropertyChange
{
public SongViewModel()
{
}
public string SongName { get; set; }
public int SongID { get; set; }
}
AlbumViewModel.cs
public class AlbumViewModel : NotifyOfPropertyChange
{
public AlbumViewModel()
{
}
public string AlbumName { get; set; }
public int AlbumID { get; set; }
}
SongListViewModel.cs
AlbumListViewModel.cs
I would like to know how 3. and 4. would have to look like to fill the album list with the album names and show corresponding songs in a second list.
With MVVM you would lose the controller and just have a ViewModel. There you would have your lists as such(including a notify property changed)
private ObservableCollection<SongData> _songList;
public ObservableCollection<SongData> SongList
{
get { return _songList; }
set { SetProperty(ref _songList, value, () => SongList); }
}
Then you would load this list at some point
public void LoadSongData(int albumID)
{
Using(YourContext _context = new YourContext)
{
SongList = new ObservableCollection(_context.songs
.Where(s => s.AlbumID == albumID)
.Select(s => new SongData
{
SongID = s.SongID,
SongName = s.SongName
})
.ToList());
}
}
I'm in a scenario WPF MVVM EF code first.
All start my application I have to initialize the two databases, but lose 10 seconds each time to do everything. there is a way to speed up?
private void InitDb()
{
var sednaComuniContext = new SednaComuniContext();
sednaComuniContext.Database.Initialize(false);//slowly
if (String.IsNullOrEmpty(Ditta) || Ditta == "BaseDb") return;
var sednaContext = new SednaContext(dbHelper.CreateConnectionString(Ditta));
sednaContext.Database.Initialize(false);//slowly
}
SednaComuniContext:
public class SednaComuniContext : DbContext,IContext
{
public static DatabaseHelper dbHelper;
static string _connection;
public SednaComuniContext()
: base(CreateConnectionString())
{
}
private static string CreateConnectionString()
{
dbHelper = new DatabaseHelper();
return dbHelper.CreateConnectionString("ArchiviComuni");
}
public SednaComuniContext(string connString)
: base(connString)
{
_connection = connString;
if (!Database.Exists())
{
Database.Initialize(true);
}
}
public DbSet<ArticoliFamiglia> ArticoliFamiglia { get; set; }
public DbSet<ArticoliGruppo> ArticoliGruppo { get; set; }
public DbSet<Articoli> Articoli { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<SednaComuniContext, Configuration>());
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
SednaContext:
public class SednaContext : DbContext,IContext //IDbContext
{
public static DatabaseHelper dbHelper;
static string _connection;
public SednaContext()
: base(_connection)
{
}
public SednaContext(string connString)
: base(connString)
{
_connection = connString;
}
public DbSet<ArticoliFamiglia> ArticoliFamiglia { get; set; }
public DbSet<ArticoliFamigliaImpostazioni> ArticoliFamigliaImpostazioni { get; set; }
public DbSet<ArticoliGruppo> ArticoliGruppo { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<SednaContext, Configuration>());
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Can an entity migration be used for that?
Since the Entity Framework team has moved to Entity Framework 6 to the EntityFramework.dll the initial load of the database slowed down considerably, some of these problems were fixed but building a model with 2 entities at a console project takes 4-5 seconds for me as well. See this open item describing part of this problem:
http://entityframework.codeplex.com/workitem/2298
The only workaround for this would be a loading screen where you show the users some fancy progress bar and display terms like loading this and that important part of the application.
So that I can store the user's screen preferences, I have ScreenSettings entity that I want to retrieve when the program starts and save when the program ends.
For this reason I don't want to keep the context open.
I am wondering about the best way to do this.
I have tried the following
however I am not comfortable with the SaveSettings function because it deletes and re-adds the object.
How do I save changes to the object without actually replacing it?
namespace ClassLibrary1
{
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
//Domain Class
public class ScreenSetting
{
#region Properties
public int Id { get; set; }
[Required]
public int WindowLeft { get; set; }
[Required]
public int WindowTop { get; set; }
#endregion
}
// Context
public class Context : DbContext
{
#region Properties
public DbSet<ScreenSetting> ScreenSettings { get; set; }
#endregion
}
// UI
public class UI
{
#region Public Methods
// Get the settings object
public ScreenSetting GetSettings(int SettingsId)
{
var Db = new Context();
ScreenSetting settings = Db.ScreenSettings.Find(SettingsId);
if (settings == null)
{
settings = new ScreenSetting { Id = SettingsId, WindowTop = 100, WindowLeft = 100 };
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
return settings;
}
// Save the settings object
public void SaveSettings(ScreenSetting settings)
{
var Db = new Context();
ScreenSetting oldSettings = Db.ScreenSettings.Find(settings.Id);
if (oldSettings == null)
{
Db.ScreenSettings.Add(settings);
}
else
{
Db.ScreenSettings.Remove(oldSettings);
Db.ScreenSettings.Add(settings);
}
Db.Dispose();
}
public void test()
{
ScreenSetting setting = this.GetSettings(1);
setting.WindowLeft = 500;
setting.WindowTop = 500;
this.SaveSettings(setting);
}
#endregion
#region Methods
private static void Main()
{
var o = new UI();
o.test();
}
#endregion
}
}
You ran into a common pattern, update or insert, which is so common that it's got a name: upsert. When a pattern is common, usually there also is a common solution.
In System.Data.Entity.Migrations there is an extension method AddOrUpdate that does exactly what you want:
public void SaveSettings(ScreenSetting settings)
{
using (var db = new Context())
{
db.ScreenSettings.AddOrUpdate(settings);
db.SaveChanges();
}
}
For example I have two entities
Class A
{
public Guid Id {get;set;}
public Guid BId {get;set;}
public B InstanceB {get;set;}
}
Class B
{
public Guid Id {get;set}
}
B is related to A, on my silver light application I am creating a new instance of A, and also a new instance of B. The new instance of B does not exist yet. But I need the instance of B on my service.
Can I do this without Entity or Association with Ria Service?
Edit:
My Class A :
public partial class lSync{
// Metadata classes are not meant to be instantiated.
private lSync() {
}
public string ConflictMessage { get; set; }
public DateTime DateInserted { get; set; }
public Guid vValuesId { get; set; }
public Guid ID { get; set; }
public bool IsConflict { get; set; }
public bool IsReadyToSync { get; set; }
public Guid SyncSet { get; set; }
public vValues vValues { get; set; }
}
My Ria Service:
[Invoke]
public lSync[] SynchvValuesFromClient(lSync[] syncs) {
bool noConflict = true;
foreach (lSync sync in syncs) {
var servervValue = GetvValuesByID(sync.vValuesId).FirstOrDefault();
var queuevValues = sync.vValues; //sync.vValues here is null, but my sync.vValuesId is not
if (servervValue== null) {
InsertvValues(queueValue);
}
else {
if (servervValue.IsServerConflict(queueValue)) {
sync.IsConflict = true;
sync.ConflictMessage = "Conflict";
noConflict = false;
break;
}
if (!servervValue.AreValuesEqual(queueValue)) {
UpdatevValues(queueValue);
}
}
}
if (noConflict) {
this.ObjectContext.SaveChanges();
}
return syncs;
}
public IQueryable<vValues> GetvValuesByID(Guid ID) {
return ObjectContext.vValues.Where(t => t.ID == ID);
}
public void InsertvValues(vValues model) {
model.ServerDate = DateTime.UtcNow;
if ((model.EntityState != EntityState.Detached)) {
this.ObjectContext.ObjectStateManager.ChangeObjectState(model, EntityState.Added);
}
else {
this.ObjectContext.vValues.AddObject(model);
}
}
public void UpdatevValues(vValuesmodel) {
model.ServerDate = DateTime.UtcNow;
this.ObjectContext.vValues.AttachAsModified(model, this.ChangeSet.GetOriginal(model));
}
:(
Edit
The order is wrong of your method :)
Make an instance of the service before creating instances of the Entities.
It should be:
public void SyncToServer() {
ContextService service = new ContextService();
var instanceA = new A();
instanceA.InstanceB = new B();
service.SubmitChanges(); //service.SaveChanges() for LinqToEntities
}
Are you reloading after a submit because only adding the [Include] attribute in the DomainService MetaData won't work. You need to do this in the DomainService for LinqToSql
public A GetA()
{
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<A>(a => a.InstanceB);
this.DataContext.LoadOptions = dlo;
return this.DataContext.APlural.FirstOrDefault( ); //don't know the plural of A.
}
LinqToEntities:
public A GetA()
{
return this.MyEntitiesContext.APlural.Include( "instanceB" ).FirstOrDefault( ); //don't know the plural of A.
}
var a = new A(){
B = new B(); //or (B)selectedItem
}
now a.Id and a.BId is 0 until you SaveChanged and return saved A