locked
Calling an SQL Function / Object reference required RRS feed

  • Question

  • Hi,
    So, I'm hacking together some changes to someone else's code.
    Never understand why cSharp MVC make everything so difficult, its a job I could do in 5 minutes in VB script, but I'm stuck using CSharp despite its awfulness.

    So, the scenario is a visitor registration database, we are adding a "limit" to the number of people who can book for a site on a particular day. The "limit" will be optional at a site level. Another scenario is that there will be a number of days in the future, you are allowed to book for, and not able to book after that date.
    I've created the relevant objects to store that data at a site level, which, although displayed in an awful way for some reason, is basically working, and stored in the database against the site.

    Now, when a booking is created for the relevant site, it simply needs to read the information from the site, lets say there is a limit of 50 people, compare that to the number of people booked for a given day, and display a warning (also defined at site level).

    I'd settle for it simply being able to read the SQL I've entered as a starting point though.
    That SQL is an a thing called "ISitesRepository", if it helps to give context is under "SiteVisitorRegister.Data\Interfaces\Repositories\SysAdmin\ISitesRepository.cs"


    It looks like this:

    public class IsFutureBookingLimitSupported
        {
             public IEnumerable<IsFutureBookingLimitSupported> GetFutureBookingLimitCheckbox(bool siteId, IDbConnection databaseConnection)
            {
                return
                    databaseConnection.Query<IsFutureBookingLimitSupported>(
                        "SELECT IsFutureBookingLimitSupported FROM [Sites] WHERE SiteId = @siteId ORDER BY Description", new { siteId });
            }
            // bool<IsFutureBookingLimitSupported> private SitesReposGetFutureBookingLimitCheckbox(string siteId);
        }

    That bit compiles OK, at least (no errors).
    BUT  - in another area, for context if it helps "VisitorRegister\SVR.WebClient\Controllers\Reg2Controller.cs"
    I simply wish to call that code, inputting the SiteId from the "model", it would seem to be easy, no idea why they make it so hard, the logical way is:
    ISitesRepository.GetFutureBookingLimitCheckbox(model.SiteId);

    Here is the way's I've tried and the errors they are giving:

    ISitesRepository.GetFutureBookingLimitCheckbox(model.SiteId); - An object reference is required for the non static field or property

    var abISitesRepository = new ISitesRepository; - Cannot create an instance of the abstract class or interface ISitesRepository
    void ISitesRepository -- Keyword void cannot be used in this context

    Not sure what else to try.

    Tuesday, November 3, 2020 8:39 AM

Answers

  • Thanks for replying, I'm sure there is a place for CSharp, and I suppose it avoids people like me writing an enormous "program" file with reems of code in it, I just find it hard to find anything, and when I do, simple things like running SQL seem unnecessarily hard, but I suppose I just need more or some training.

    Anyway I tried a version of what you propose, but it seems like the ISitesRepository is not declared, or rather, it's set to something else "SitesVisitorRegister.Data.Classes.Repositories.SysAdmin.SiteRepository.cs"

    Rather than what I need:
    "SiteVisitorRegister.Data\Interfaces\Repositories\SysAdmin\ISitesRepository.cs"

    So I've tried defining my own, here is some code snippets for the original and mine, ideally I'd give it a different name, but it won't let me:

    \\original
    private readonly ISitesRepository _sitesRepository;

    \\HERE I'd like private readonly ISitesRepositoryActual say, but that gives an error (type of namespace not found
           private readonly ISitesRepository _ActualIsitesRepository;

    Then a "param":

    /// <param name="sitesRepository"></param>
            /// <param name="ISitesRepositoryActual"></param>

    Then:
    \\In a bigger bit of code, I can provide it all if that helps:

    ISitesRepository sitesRepository, ISitesRepository ISitesRepositoryActual,

    Then:

     _sitesRepository = sitesRepository;
                _ActualIsitesRepository = ISitesRepositoryActual; 

    But what happens is, it uses the wrong one.
    I've tried putting the SQL in the wrong one, but that doesn't work either, something about a return type.

    Tuesday, November 3, 2020 9:32 AM

All replies

  • Never understand why cSharp MVC make everything so difficult, its a job I could do in 5 minutes in VB script,

    It all depends on how big and complex your program is. VB Script is good for small and trivial pieces of programming. But when your application has millions of lines across hundreds or thousands of projects, the C# compiler will immediately point out many mistakes that would take you hours and hours to find out if you were programming in a scripting language. Of course, this presumes that you actually understand what it is doing and how it works; otherwise you will spend lots of time wondering why the compiler points out a mistake where you think that there is none.

    So let´s analyze what is the problem in this particular case. You are writing this:

    ISitesRepository.GetFutureBookingLimitCheckbox(model.SiteId);

    where ISitesRepository is an interface. However, an interface has no implementation; it´s just a way to abstract one or more classes, so that any of these the various classes can be invoked by a single piece of code that declares its variables with the type of the interface. This allows you to do some pretty advanced things such as injecting dependencies including fakes for the units tests... which won't make any sense to you if you are used to programming in a scripting language, but will save thousands of hours of work if properly implemented when working in a large project.

    So, if the interface does not have any implementation, how can you execute a method through an interface? You cannot do interface.method, because the method is not implemented in the interface. The trick is that you need to instance a class that implements the interface, and then you can execute the method in the class:

    ISitesRepository sitesRepository = new SitesRepository();

    sitesRepository.GetFutureBookingLimitCheckbox(model.SiteId);

    Of course, the preceding presumes that SitesRepository is the class that implements ISitesRepository, this is not visible in your code.

    In a real, large program, you would set up a class to resolve the dependencies (there are many existing libraries for doing this), so that once set up properly it would automatically resolve the interface to the class that implements it.

    I'm sorry and I apologize in advance if I appear to be a bit harsh at pointing out "complex" things and trying to classify them as "better" than the simple things done in scripting. It's not that one approach is better than the other, it's an "it depends". When you are building a large project and you need to be able to put it all together in a reliable way, you need to embrace the fact that you will need to use tools that are more powerful than what you would use for a simple project. Even if such tools are more complex to learn, in the long run they save more time than they require at the beginning.

    Tuesday, November 3, 2020 9:04 AM
  • Thanks for replying, I'm sure there is a place for CSharp, and I suppose it avoids people like me writing an enormous "program" file with reems of code in it, I just find it hard to find anything, and when I do, simple things like running SQL seem unnecessarily hard, but I suppose I just need more or some training.

    Anyway I tried a version of what you propose, but it seems like the ISitesRepository is not declared, or rather, it's set to something else "SitesVisitorRegister.Data.Classes.Repositories.SysAdmin.SiteRepository.cs"

    Rather than what I need:
    "SiteVisitorRegister.Data\Interfaces\Repositories\SysAdmin\ISitesRepository.cs"

    So I've tried defining my own, here is some code snippets for the original and mine, ideally I'd give it a different name, but it won't let me:

    \\original
    private readonly ISitesRepository _sitesRepository;

    \\HERE I'd like private readonly ISitesRepositoryActual say, but that gives an error (type of namespace not found
           private readonly ISitesRepository _ActualIsitesRepository;

    Then a "param":

    /// <param name="sitesRepository"></param>
            /// <param name="ISitesRepositoryActual"></param>

    Then:
    \\In a bigger bit of code, I can provide it all if that helps:

    ISitesRepository sitesRepository, ISitesRepository ISitesRepositoryActual,

    Then:

     _sitesRepository = sitesRepository;
                _ActualIsitesRepository = ISitesRepositoryActual; 

    But what happens is, it uses the wrong one.
    I've tried putting the SQL in the wrong one, but that doesn't work either, something about a return type.

    Tuesday, November 3, 2020 9:32 AM
  • Surely someone can help me?

    How can this be so hard, just one line SQL lookup, I don't care, where we have to put the SQL, whereever I put it it doesn't work, here's one example that compiles; but the calling code doesnt compile:

    In SiteVisitorRegister.Data\Classes\Repositories\SysAdmin\SitesRepository.cs

        public class IsFutureBookingLimitSupported
            {
                //(string SiteId, IDbConnection databaseConnection, IDbTransaction transaction)
                //IEnumerable<IsFutureBookingLimitSupported> GetFutureBookingLimitCheckbox(string SiteId, IDbConnection databaseConnection, IDbTransaction transaction)
                bool GetFutureBookingLimitCheckbox(string SiteId, IDbConnection databaseConnection)
                {
                    //    throw new NotImplementedException();
                    //return
                    var siteId = "1234";
                    var something = databaseConnection.Query<IsFutureBookingLimitSupported>(
                            "SELECT IsFutureBookingLimitSupported FROM [Sites] WHERE SiteId = @siteId ORDER BY Description", new {siteId });
                    string somethingasastring = something.ToString();
                    bool IsFutureBookingLimitSupported = Convert.ToBoolean(somethingasastring);
                    return
                        IsFutureBookingLimitSupported;
                    //something.Single();
                    //throw new NotImplementedException();
                    //}
                }
            }

    It forced me to make this "Class" though I didn't want to.

    That code compiles.
    But then try and call it, a nightmare, everywhere you call it from you need another data connection, calling code apparently has to be identical, this is so dumb, I can't believe it works like this:
    This is what I want to do with it:

    public ActionResult CreateRegistration(NewRegistration model)
            {
                //ISitesRepository.Get
                //from the called code:string SiteId, IDbConnection databaseConnection//SVR.Data.Classes.Repositories //IDbConnection databaseConnection
                var something = _sitesRepository.GetFutureBookingLimitCheckbox(model.SiteId, IDbConnection databaseConnection );// - namespace cannot be found, despite assigned above.
                string somethingasastring = something.ToString();
                model.IsFutureBookingLimitSupported = Convert.ToBoolean(somethingasastring);

    //some other things
    }
    This gives error: the name databaseConnection does not exist in the current context.

    It DOES EXIST! THATS WHY I WROTE IT THERE. IF IT DIDNT EXIST IT WOULD LOOK LIKE THIS:

    Tuesday, November 3, 2020 11:41 AM
  • You should post to the correct forum where developers  use the repository pattern and the AsP.NET MVC Ui design pattern.

    https://forums.asp.net/

    Tuesday, November 3, 2020 12:52 PM
  • I just put the SQL directly in the part that was supposed to be calling it, which seems to work fine, and gets round the ludicrous restrictions in MVC \C Sharp.

    Thought this was a reasonable place to post to be honest.

    In any case I'll close it since I've got round the restrictions.

     
    Wednesday, November 4, 2020 8:32 AM