Почему в запросах DAL2 отсутствуют имена полей и отображается SELECT NULL?

Я создаю модуль для использования в DNN 7+ и хотел бы использовать DAL2 для доступа к данным, но у меня возникли проблемы с выбором элементов из базы данных.

Мой код успешно подключается к базе данных, но запросы, генерируемые DAL2, не включают имена полей в таблице базы данных. Я запускаю SQL Server Profiler, чтобы посмотреть, что попадает в базу данных, и увидеть запросы, начинающиеся с «SELECT NULL FROM Product...». Я ожидаю увидеть "SELECT * FROM Product..." или "SELECT ProductCode FROM Product..."

Чтобы изолировать проблему и иметь возможность включить полный пример кода, я сократил свой тест до следующего: У меня есть файл Product.cs:

using System.Web.Caching;
using DotNetNuke.ComponentModel.DataAnnotations;

namespace MyModule.Components
{
    [TableName("Product")]
    [PrimaryKey("productCode")]
    [Cacheable("MYMODULE_Product_", CacheItemPriority.Default, 20)]
    [Scope("productCode")] //different values here did not change the result.
    public class Product
    {
        public string productCode;
    }
}

У меня есть файл ProductRepository.cs:

using DotNetNuke.Data;

namespace MyModule.Components
{
    public class ProductRepository
    {
        private const string EXTERNAL_DB_CONNECTION_STRING = "MY_DB_CONNECTIONSTRING_NAME";

        public Product GetProduct(string productCode)
        {
            Product t;
            using (IDataContext ctx = DataContext.Instance(EXTERNAL_DB_CONNECTION_STRING))
            {
                var rep = ctx.GetRepository<Product>();
                t = rep.GetById(productCode);
            }
            return t;
        }
    }
}

Я использую эти два файла в своем представлении со следующим кодом:

ProductRepository productRepo = new ProductRepository();    
Product product = (Product)productRepo.GetProduct("MYCODE");

Во время выполнения этого кода я отслеживаю с помощью SQL Server Profiler и вижу, что выполняется следующий запрос:

exec sp_executesql N'SELECT NULL FROM [Product] WHERE [productCode]=@0',N'@0 nvarchar(4000)',@0=N'MYCODE'

Я не знаю, почему приведенный выше запрос выбора выбирает NULL. Я ожидаю список полей продукта из файла Product.cs или символ *.

Мое определение поля базы данных (как видно из древовидного представления Microsoft SQL Server Management Studio) для productCode:

productCode(PK, varchar(50), not null)

Я подключаюсь к внешней базе данных, а данные не связаны с конкретным модулем или порталом. Вот почему я указываю «productCode» в качестве Scope. Я не уверен, как правильно использовать Scope, когда данные не привязаны к порталу или модулю. Чтобы убедиться, что проблема не связана с атрибутом Scope в файле Product.cs, я протестировал переменную Scope со значениями «PortalId», «ModuleId», «productCode» и «Nothing». Все эти значения приводили к тому, что один и тот же запрос отображался в профилировщике SQL Server.

Я также проверил, полностью удалив атрибут Scope. Когда атрибут Scope не был включен, я увидел следующий запрос в SQL Server Profiler:

SELECT NULL FROM [Product]

Я не уверен, почему предложение WHERE было удалено при исключении атрибута Scope, но именно это показали результаты теста.

Эти тесты с атрибутом Scope заставили меня поверить, что это не связано с проблемой «SELECT NULL», которую я вижу, но я хотел включить ее сюда для полноты картины.

Может ли кто-нибудь помочь, почему это создает выбор с NULL и как мне заставить его выбирать мои данные?

Спасибо!


person RacerNerd    schedule 08.10.2013    source источник


Ответы (3)


Я нашел ответ, но хотел бы немного помочь понять, почему это работает. Во-первых, чтобы подключить столбец данных, я изменил класс Product.cs на это:

using System.Web.Caching;
using DotNetNuke.ComponentModel.DataAnnotations;
namespace MyModule.Components
{
    [TableName("Product")]
    [PrimaryKey("productCode")]
    [Cacheable("MYMODULE_Product_", CacheItemPriority.Default, 20)]
    [Scope("productCode")]  //tried different values here and nothing changed but excluding this caused more problems
    public class Product
    {
        public string productCode { get; set; };
    }
}

Разница здесь заключается в добавлении методов доступа get и set. Это сбивает меня с толку, так как я думал, что ранее использованная строка

public string productCode;

был бы функционально эквивалентен

public string productCode { get; set; };

в контексте. Я думал, что «получить» и «установить» не нужны, если только доступ к переменной не будет ограничен одной из этих операций или если потребуется более обширная обработка при установке или получении защищенного значения.

Я что-то упустил в своем понимании получения и установки или я правильно это понимаю? Требуются ли здесь get и set только для совместимости с DAL2?

person RacerNerd    schedule 08.10.2013

гонщик ботан,

Нужны правильные аксессуары:

public string productCode { get; set; }; 

vs

public string productCode;

Я пропустил это! Хороший улов.

Я считаю, что причина использования явных методов получения и установки заключается не только в том, чтобы следовать соглашению о POCO Entity Framework, но также я считаю, что когда вы явно используете методы получения и установки, вы сообщаете CLR, что член класса является свойством, а не общедоступной переменной. На поверхности они работают одинаково. Но если PetaPoco использует отражение для сопоставления свойств класса с полями, возможно, поэтому оно и требуется.

person DotNetNuclear    schedule 08.10.2013

Я только что заметил, что у вас есть только один атрибут, сопоставленный с полем в вашей таблице. Он помечен как область действия и первичный ключ. Scope — это единица измерения, в которой вы кэшируете свои наборы элементов. Нет смысла делать его таким же, как ваш первичный ключ. Обычно это идентификатор портала, идентификатор модуля, идентификатор категории или что-либо, представляющее набор записей о продуктах.

Тем не менее, попробуйте полностью удалить атрибут Scope — по крайней мере, на данный момент. Кроме того, есть ли в вашей таблице поле под названием «код продукта». Я считаю, что PetaPoco чувствителен к регистру, поэтому он должен точно совпадать. В противном случае вам нужно добавить атрибут сопоставления полей [ColumnName("Product_Code")] над элементом productCode, чтобы он соответствовал имени поля в вашей таблице.

person DotNetNuclear    schedule 08.10.2013
comment
Я упоминаю в OP, что в атрибуте Scope использовалось несколько разных значений. Когда я полностью удаляю Scope, предложение WHERE не включается в SQL. Я не знаю, почему это происходит, и хотел бы знать. Поскольку мои данные не подключены к модулю или порталу, я не уверен, какое значение следует включить в область действия. Что я точно знаю, так это то, что исключение атрибута Scope, похоже, не работает, и любое другое значение, которое я включил (в моем ограниченном тестировании), не повлияло на SQL. - person RacerNerd; 09.10.2013