0

My application has a business logic layer, and a data access layer. I want to give only the data access layer access to the database model. Now, I can easily do this, but then my UI classes cannot access the database classes like Reminder:

namespace Database
{
    using System;
    using System.Collections.Generic;

    public partial class Reminder
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string Date { get; set; }
        public string RepeatType { get; set; }
        public string Note { get; set; }
        public long Enabled { get; set; }
        public string SoundFilePath { get; set; }
        public string PostponeDate { get; set; }
        public Nullable<long> EveryXCustom { get; set; }
        public string RepeatDays { get; set; }
        public Nullable<long> DayOfMonth { get; set; }
    }
}

which is inside the database class library

enter image description here

I use this reminder class to store reminders. In my UI classes I use this class for various reasons.

To make use of this Reminder class, I simply add a reference to the class library that needs to use it. This works fine, but the problem is that every class library that references this, can alter the database like this.

If I'm not using Entity Framework, I could simply have a Reminder class outside the model (because there is no model) and load reminders from the database into that and extract them without using Entity Framework.

Here's an example of why I need to use the Reminder class in my UI classes (this is just a small code sample of one UI class)

This code is inside a timer that ticks every 30 seconds

// We will check for reminders here every 30 seconds.
foreach (Reminder rem in BLReminder.GetReminders())
{
    // Create the popup. Do the other stuff afterwards.
    if(rem.PostponeDate != null && Convert.ToDateTime(rem.PostponeDate) <= DateTime.Now && rem.Enabled == 1)
    {
        allowRefreshListview = true;

        // temporarily disable it. When the user postpones the reminder, it will be re-enabled.
        rem.Enabled = 0;
        BLReminder.EditReminder(rem);

        MakePopup(rem);
    }
    else if(Convert.ToDateTime(rem.Date.Split(',')[0]) <= DateTime.Now && rem.PostponeDate == null && rem.Enabled == 1)
    {
        allowRefreshListview = true;

        // temporarily disable it. When the user postpones the reminder, it will be re-enabled.
        rem.Enabled = 0;
        BLReminder.EditReminder(rem);

        MakePopup(rem);
    }
}    

GetReminders will do get the reminders from the database and put them in reminder objects

using (RemindMeDbEntities db = new RemindMeDbEntities())
{                
    localReminders = (from g in db.Reminder select g).ToList();
    db.Dispose();                
}

2 Answers 2

1

You can create separate project called i.e. Shared and put there all classes which are used in many projects. Then you need to reference this project by UI project and data access project (and by others which use these classes).

Both will have access to shared classes and UI won't be able to call data access layer directly.

You can also create interface outside of data access layer but if your classes are DTOs (Data Transfer Object) first option will be better.

Sign up to request clarification or add additional context in comments.

10 Comments

> put there all classes which are used in many projects. Which classes? The model's classes? I dont think that's possible
@stefan, you can have model classes in another project, see nullablecode.com/2013/09/… and stackoverflow.com/questions/2464909/…
I think this is the best solution, but now im getting weird errors. I followed to guide in your link, and now my entities don't know the classes.. visual studio's code completion does know it though. imgur.com/gPxjbJF.gif with the error being cannot convert from 'Database.Entity.Reminder' to 'Reminder' , Database.Entity being the class library with the seperated model classes The Reminder from the Entities is still inside Database(not Database.Entity) from the RemindMeDbModel.Context.cs
edit: figured it out. i didnt just have to set a custom tool on the .Context.tt, i also had to remove the model.context.cs from the old project
Currently trying to fix the new error "Unable to load the specified metadata resource." ...
|
1

If im not using the entity framework, i could simply have a reminder class outside the model

You could create an interface instead of a class outside of the model in a shared assembly:

public interface IReminder
{
    public long Id { get; }
    public string Name { get; }
    public string Date { get; }
    public string RepeatType { get; }
    public string Note { get; }
    public long Enabled { get; }
    public string SoundFilePath { get; }
    public string PostponeDate { get; }
    public Nullable<long> EveryXCustom { get; }
    public string RepeatDays { get; }
    public Nullable<long> DayOfMonth { get; }
}

Your Entity can than implement the interface:

public partial class Reminder : IReminder
{
    //...
}

Maybe you want to make your Entities only internal visible and expose public service methods like IEnumerable<IReminder> GetReminders()

3 Comments

Hmm, i found this very interesting so i went out and tried it, but then i ran into problems. I can't make new instances of an interface, so i cant assign data to it. I also can't call methods like DLReminders.GetReminders() in the business logic layer anymore, because that will give me this errror i.imgur.com/bzCi4kq.png, which suggests the solution that im trying to avoid
@stefan for the first problem, simple create a class that is derived from IReminder and create a instance from it. For the second problem: Don't confuse seperation of concerns with seperation of references ;) If your business layer needs your data layer, then it also needs a reference to it. However, I would go for a DataService that exposes only the interface, The Business layer consumes that data service instead of the raw entities.
but, isnt it supposed to be so that the business logic layer can not access the database? Like this image codeguru.com/images/article/19539/030318_01.gif

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.