4
\$\begingroup\$

I'm working on updating a GitHub project that I use at work, but I think the person abandoned the project as there is a pull request for it since 2014. At work we use a Repository pattern with NHibernate and mappings and so forth but this project they use Entity 4.? I had to update the project to use .Net 4.6.1, and because of that I had to update to Entity 5.0. (I know I could have done 6.0 or greater, but I don't want to break the existing code and 6.0 gave me compiler errors which I don't know how to fix yet). The existing DataContext has a DBSet for all 3 tables (which I don't like) so I'm slowly splitting that into individual repositories. Here is what I have thus far. First the POCO, and interface for said repository

public class LogSubscription
{
    public int LogSubscriptionId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public string PluginTypeName { get; set; }
}
public interface ISubscriptionRepository: IDisposable
{
    LogSubscription GetSubscription(string name);
    void SaveSubscription(LogSubscription logSubscription);
    void DeleteSubscription(LogSubscription logSubscription);
}

I made it like that so I can easily mock out the repository without having to drag Entity with me. Now the implementation. Sorry if it makes your eyes bleed from any blaring code smells.

LogSubscriptionDataContext

internal class LogSubscriptionDataContext : DbContext
{
    public LogSubscriptionDataContext()
        :base("SourceLog")
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<LogSubscriptionDataContext>());
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Models.LogSubscriptionDto>().ToTable("LogSubscription");
    }
}

SubscriptionRepository

public class SubscriptionRepository : ISubscriptionRepository
{
    private readonly DbContext _context;
    private readonly IDbSet<LogSubscriptionDto> _logSubscriptions;

    public SubscriptionRepository()
    {
        _context = new LogSubscriptionDataContext();
        _logSubscriptions = _context.Set<LogSubscriptionDto>();
    }

    public LogSubscription GetSubscription(string name)
    {
        return (LogSubscription)_logSubscriptions.Find(name);
    }

    public void SaveSubscription(LogSubscription logSubscription)
    {
        if (_logSubscriptions.Find(logSubscription.Name) != null)
            return;

        _logSubscriptions.Add((LogSubscriptionDto)logSubscription);

        _context.SaveChanges();
    }

    public void DeleteSubscription(LogSubscription logSubscription)
    {
        _logSubscriptions.Remove(_logSubscriptions.Find(logSubscription.Name));
        _context.SaveChanges();
    }

    private bool disposedValue = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                _context.SaveChanges();
                _context.Dispose();
            }
            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
    }
}

LogSubscriptionDto

[Table("LogSubscription")]
internal class LogSubscriptionDto
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int LogSubscriptionId { get; set; }
    [Key]
    public string Name { get; set; }
    [Required]
    public string Url { get; set; }
    [Required]
    public string PluginTypeName { get; set; }

    public LogSubscriptionDto()
    {
    }
    public LogSubscriptionDto(string name)
    {
        Name = name;
    }
    public LogSubscriptionDto(Core.Models.LogSubscription subscription)
    {
        LogSubscriptionId = subscription.LogSubscriptionId;
        Name = subscription.Name;
        PluginTypeName = subscription.PluginTypeName;
        Url = subscription.Url;
    }

    public static explicit operator LogSubscriptionDto(Core.Models.LogSubscription subscription)
    {
        return new LogSubscriptionDto(subscription);
    }
    public static explicit operator Core.Models.LogSubscription(LogSubscriptionDto subscription)
    {
        return (subscription == null) ?
            null :
            new Core.Models.LogSubscription
            {
                LogSubscriptionId = subscription.LogSubscriptionId,
                Name = subscription.Name,
                PluginTypeName = subscription.PluginTypeName,
                Url = subscription.Url,
            };
    }
}

Integration Test

[TestFixture]
public class SubscriptionRepositoryTests
{
    [Test]
    public void CanSaveSubscription()
    {
        var logSubscription = new LogSubscription
        {
            Name = "Robert",
            PluginTypeName = "Git",
            Url = "http://codereview.stackexchange.com/"
        };
        LogSubscription subscription = null;
        subscription = CRD_Object(logSubscription);
        Assert.That(subscription.Name, Is.EqualTo(logSubscription.Name));
        Assert.That(subscription.PluginTypeName, Is.EqualTo(logSubscription.PluginTypeName));
        Assert.That(subscription.Url, Is.EqualTo(logSubscription.Url));
        Assert.That(subscription, Is.Not.EqualTo(logSubscription));
    }

    private static LogSubscription CRD_Object(LogSubscription logSubscription)
    {
        LogSubscription subscription;
        using (Core.Repositories.ISubscriptionRepository repo = new SubscriptionRepository())
        {
            repo.SaveSubscription(logSubscription);
            subscription = repo.GetSubscription("Robert");
            repo.DeleteSubscription(logSubscription);
            Assert.That(repo.GetSubscription("Robert"), Is.Null);
        }

        return subscription;
    }
}

There are three things I'm up in the air about. One is getting the Subscription by its primary key. I feel like I should pass in the POCO, then find by the primary key (I tried passing in the Dto in the find method but it said it needed a scaler object). The other is setting the initializer in the DataContext. I just don't know where to put it, and I need it because Entity was throwing an exception saying it couldn't change the table or something because I changed my Dto. Lastly I'm thinking I'm going to remove the Id because in the UI its not used, and in the Find method it isn't used. The UI relies on the name of the subscription so in my opinion 3 strikes and you are out. Thoughts?

\$\endgroup\$
  • 1
    \$\begingroup\$ Note that ts is not always reasonable to implement a repository pattern on top of DbContext. See also that discussion. \$\endgroup\$ – JanDotNet Oct 4 '16 at 9:07
3
\$\begingroup\$

The existing DataContext has a DBSet for all 3 tables (which I don't like) so I'm slowly splitting that into individual repositories.

This is a really bad idea. A repository should encapsulate the data access and make it easier to use.

Usually tables in a database are related but if you split it into single table per repository you won't be able to use the relationsships. How are you going to join any tables?

A repository represents a storage like a database not a single table. I really discourange from splitting it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.