Jdbi: dropwizard-jdbi3 كيفية الحصول على Handle ()؟

تم إنشاؤها على ٢١ يونيو ٢٠١٨  ·  15تعليقات  ·  مصدر: jdbi/jdbi

أنا أستخدم Dropwizard-jdbi3 لإنشاء واجهة برمجة التطبيقات الخاصة بي ، وأنا أستخدم jdbi.onDemand(myDao.class) للحصول على مثيل DAO الخاص بي. لا أستطيع فهم كيفية الحصول على handle لإجراء استعلامات SSQL التي لا يمكن إجراؤها باستخدام التعليقات التوضيحية.

طريقة التشغيل

<strong i="9">@Override</strong>
    public void run(MlsConfiguration configuration, Environment environment) throws ClassNotFoundException {

        final JdbiFactory factory = new JdbiFactory();
        final Jdbi jdbi = factory.build(environment, configuration.getDatabaseAppDataSourceFactory(), "mysql");

        MlsdataDao dao = jdbi.onDemand(MlsdataDao.class);
        environment.jersey().register(new MlsResource(dao));
    }

DAO

public interface MlsdataDao extends SqlObject{

    @RegisterBeanMapper(MlsListing.class)
    List<MlsListing> getMlsListings(MlsListingParameters mlsListingParameters);

    // NOT QUITE CLER ON HOW TO GET THE HANDLE ??
   default Handle gettingHandle() {
        return this.getHandle();
    }

}

الموارد

@Path("/")
@Produces(MediaType.APPLICATION_JSON)
<strong i="16">@Api</strong>
public class MlsResource implements MlsdataDao {

    MlsdataDao mlsdataDao;

    <strong i="17">@Inject</strong>
    public MlsResource(MlsdataDao mlsdataDao) {
        this.mlsdataDao = mlsdataDao;
    }
    public MlsResource() {}
    <strong i="18">@GET</strong>
    <strong i="19">@Timed</strong>
    @Path("mls-listings")
    public List<MlsListing> getMlsListings(<strong i="20">@BeanParam</strong> MlsListingParameters mlsBeanParam) {

        Handle handle = this.getHandle(); 
      // some complicated SQL query i want to execute using the handle and other code
  }

    <strong i="21">@Override</strong>
    public Handle getHandle() {
        return mlsdataDao.gettingHandle();
    }

}

question

ال 15 كومينتر

قبل قراءة الباقي ، إذا قلت

كيفية الحصول على المقبض

أو

التي لا يمكن إجراؤها باستخدام التعليقات التوضيحية

ثم لا أعتقد أن استخدام SqlObject API هو السبيل للذهاب ، بحكم التعريف ... يُقصد من SqlObjects عدم الحاجة إلى الاهتمام بالمقابض وما شابه ، ولا يمكنهم فعل أشياء تستنتج أنهم لا يستطيعون القيام بها ...

مما يبدو أنك تحاول القيام به ، أظن أنك لا تفهم تمامًا كيف من المفترض أن تعمل SqlObjects و Jdbi APIs المعنية. هل قرأت الدليل على http://jdbi.org/ ؟ إنها مفيدة بشكل مدهش بمجرد أن تحصل على مفاهيم جدبي.

public interface Dao {
  // this query will likely need to use bean argument binding like :p.foo
  @Query("select * from etc etc")
  @RegisterBeanMapper(MlsListing.class)
  List<MlsListing> getMlsListings(MlsListingParameters p);
}
Dao dao = jdbi.onDemand(Dao.class);

List<MlsListing> listings = dao.getMlsListings(parameters);

يمكن أيضًا أن يكون List<MlsListing> listings = jdbi.withExtension(Dao.class, dao -> dao.getMlsListings(params));

يجب عليك حقن مثيل Jdbi واستخدامه لإنشاء مثيل واجهات الاستعلام التوضيحية الخاصة بك على الفور ، أو حقن onDemand SqlObjects التي ستفتح مقبض لك في الخلفية كلما استدعت أساليبها.

إذا كنت بحاجة إلى دمج استعلامات متعددة و / أو منطق جافا في معاملة واحدة (تتطلب معالجة واحدة) ، فأنت بحاجة إلى الاستفادة من الأساليب الافتراضية للواجهة مثل ذلك (مأخوذ مباشرة من مشروعي الخاص):

public interface Dao {
    <strong i="22">@CreateSqlObject</strong>
    JdbiSaleQueries saleQueries();
    <strong i="23">@CreateSqlObject</strong>
    JdbiSaleDetailQueries saleDetailQueries();
    <strong i="24">@CreateSqlObject</strong>
    JdbiClientQueries clientQueries();

    <strong i="25">@Override</strong>
    <strong i="26">@Transaction</strong>
    default UUID create(UUID clientId) {
        UUID saleId = UUID.randomUUID();

        Client client = clientQueries().get(clientId);
        if (client.isDealer()) {
            saleQueries().createForDealer(saleId, clientId);
        } else {
            saleQueries().createForClient(saleId, clientId);
        }

        return saleId;
    }
}

حيث *Queries عبارة عن واجهات بها استعلام توضيحي ، وقم بحقن مثيلات onDemand من Dao في كائنات الخدمة طويلة العمر (أو احتفظ بنسخة Jdbi طويلة العمر حولها وقم بإنشاء Dao أثناء التنقل).

يمكنك أيضًا عمل jdbi.open() للحصول على مثيل للمقبض يمكنك بعد ذلك الاستعلام عنه والقيام بما تريد به ، ولكن هذا غير مستحسن. من الأفضل استخدام jdbi.useHandle(handle -> { // do stuff here }) على الأقل ، حتى لا تضطر إلى تذكر إغلاق المقبض. يمكن أيضًا استخدام jdbi.useTransaction(tx -> {...}) لتشغيل استعلامات منطقية وجذابة في معاملة واحدة مقابل مقبض دون الحاجة إلى استخدام SqlObjects.

هل هذا يوضح لك الأشياء؟ ربما يمكنك إعادة صياغة مشكلتك ، وتحديد التفاصيل مثل استعلامك وما تريد من Jdbi أن يفعله لك ، وترك المخاوف الخارجية مثل نموذج خادم التطبيق الخاص بك؟

الإجابة المباشرة على سؤالك كما هو مذكور ، هي أنه من خلال وراثة فصلك الدراسي أو واجهتك من النوع SqlObject ، يمكنك الوصول إلى getHandle() خلال الميراث. TheRealMarnes محق تمامًا ، رغم ذلك - فهذه فتحة هروب لا يُقصد استخدامها بشكل عام. إذا لم تتمكن من تكوين استفساراتك ببساطة على أنها تعويذات SqlObject ، فيجب أن تفضل الرجوع إلى الأمر الكلاسيكي Handle use مباشرة. أقوم بإغلاق المشكلة كما تمت الإجابة عنها ، ولكن لا تتردد في مواصلة المناقشة أو المتابعة هنا.

TheRealMarnes و stevenschlansker ، شكرًا لاستجابتك ، إنه بالتأكيد أكثر وضوحًا بالنسبة لي الآن. حقن مثيل Jdbi واستخدامه لتشغيل استعلاماتي مثل ،

jdbi.withHandle(handle ->handle.createQuery("select * from table1 limit 10").mapTo(String.class).list());

دون استخدام SqlObject عملت بالنسبة لي.

شكرا.

sudharshankakumanu لما يستحق ، هذا الاستعلام الدقيق الذي كتبته هناك يجب أن يعمل فقط في SqlObject أيضًا.

TheRealMarnes هاها لا ، كان هذا فقط للاختبار. لا بد لي من استبدالها ببيان معدة مع الارتباطات.

حسنًا ، في معظم الحالات ، يجب أن يعمل كل هذا بشكل جيد أيضًا. أنا فضولي الآن. هل تمانع في مشاركة الاستعلام والمعلمات الدقيقة والأشياء التي تريد استخدامها حتى نتمكن من رؤيتها حول صبها في SqlObject من أجل ذلك؟

في الحقيقة لا يمكنني التفكير في أي شيء من شأنه أن يعمل في بيان بطلاقة ولكن ليس في sqlobject. لن يتم تعيين المنطق ذي الحالة فقط ...

بالتأكيد،

SELECT  (ZIP, PROPERTY_TYPE,...  (known at runtime on what user wants to select) ) FROM myTable

WHERE ( (ZIP in zipcodes) or (NEIGHBORHOOD_ID in neighborhoodIds) or (CITY_ID in cityIds) or (SUBDIVISION_ID in subdivisionIds) ) 
AND (LISTING_AGENT_ID in listingAgentIds (known at runtime if I have to do AND on this field, skip if user did not provide any list of listingAgentIds, same with every field. ))
AND (LISTING_OFFICE_ID in listingOfficeIds)
AND (COMPANY_ID in listingCompanyIds)
AND (PROPERTY_TYPE in propertyTypes)
AND (LISTING_PRICE >= minPrice)
AND (LISTING_PRICE <= maxPrice)
AND (BEDROOMS >= minBeds)
AND (BEDROOMS <= maxBeds)
AND (FULL_BATH >= minBaths)
AND (FULL_BATH <= maxBaths)

آه ، إذن أنت تتعامل مع المنطق الشرطي. سيكون ذلك صعبًا ، نعم. يمكن أن تساعدك TemplateEngines الصحيحة ، مثل الشارب ، أو العلامة الحرة التي أفترضها. ربما لا يستحق التعقيد الإضافي بالرغم من ذلك.

أوه ، عظيم ، سوف أنظر إليهم. شكرا لك مرة أخرى.

TheRealMarnes ،

لدي تطبيق الاستعلام الخاص بي على النحو التالي:

 Map<String, Object> contact = new HashMap<>();
        // Dummy code to create hash map, this is also actually generated at runtime.
        List<String> list = new ArrayList<>();
        list.add("94536");
        list.add("95035");

        contact.put("zipcodes", list);
        contact.put("minBeds", 3);
        // sqlQuery is runtime generated (ex: SELECT * FROM myTable WHERE ZIP IN (<zipcodes>)) AND bedrooms >= :minBeds
        List<MlsListing> sources = jdbi.withHandle(handle ->
                handle.registerRowMapper(FieldMapper.factory(MlsListing.class)).createQuery(sqlQuery)
                        .bindMap(contact)
                        .mapTo(MlsListing.class)
                        .list());

هذا يرمي لي خطأ:

WARN  [2018-06-27 23:53:45,470] graphql.execution.SimpleDataFetcherExceptionHandler: Exception while fetching data (/getMlsListings) : Error rendering SQL template: 'SELECT * FROM mlsdata WHERE ZIP IN (<zipcodes>)' [statement:"SELECT * FROM mlsdata WHERE ZIP IN (<zipcodes>)", rewritten:"null", parsed:"null", arguments:{ positional:{}, named:{}, finder:[{<zipcodes>=[94536, 95035]}]}]
! org.jdbi.v3.core.statement.UnableToCreateStatementException: Undefined attribute for token '<zipcodes>' [statement:"SELECT * FROM mlsdata WHERE ZIP IN (<zipcodes>)", rewritten:"null", parsed:"null", arguments:{ positional:{}, named:{}, finder:[{<zipcodes>=[94536, 95035]}]}]
! at org.jdbi.v3.core.statement.DefinedAttributeTemplateEngine.render(DefinedAttributeTemplateEngine.java:54)
! ... 61 common frames omitted
! Causing: org.jdbi.v3.core.statement.UnableToCreateStatementException: Error rendering SQL template: 'SELECT * FROM mlsdata WHERE ZIP IN (<zipcodes>)' [statement:"SELECT * FROM mlsdata WHERE ZIP IN (<zipcodes>)", rewritten:"null", parsed:"null", arguments:{ positional:{}, named:{}, finder:[{<zipcodes>=[94536, 95035]}]}]

حاولت استخدام شيء مثل هذا:

 List<MlsListing> sources = jdbi.withHandle(handle ->
                handle.registerRowMapper(FieldMapper.factory(MlsListing.class)).createQuery(sqlQuery)
                           .bindList("cityIds", mlsBeanParam.cityIds)
                          .bindList("neighborhoodIds", mlsBeanParam.neighborhoodIds)
                          .bindList("zipcodes", mlsBeanParam.zipcodes)
                          .bind("minBeds" , mlsBeanParam.minBeds)
                        .mapTo(MlsListing.class)
                        .list());

هذا يعطيني استثناءً للمؤشر الفارغ (قد يكون ذلك بسبب إمكانية أن تكون سمة cityIds أو أي سمة mlsBeanParam أخرى خالية في وقت التشغيل).

آسف للتعليق هنا مباشرة. يمكنني نشر هذا كسؤال منفصل إذا كنت تعتقد أن ذلك يساعد.

يوجد نوعان مختلفان من معامِلات الاستعلام في jdbi: السمات والارتباطات . السمات مخصصة لمعالجة السلسلة ، سيتم تقديمها بواسطة TemplateEngine (DefinedAttributeTemplateEngine ، الافتراضي ، يعرض تلك التي تحتوي على بناء جملة <foo> ) ، ويجب أن تكون define d. الروابط هي معلمات عنصر نائب كلاسيكي لـ sql ( ? thingies) ، ستكون مرتبطة بـ SqlParser (الافتراضي هو ColonPrefixSqlParser ، الذي يعالج بناء الجملة :foo ) ، ويجب أن يكون bind ed . انظر واجهة الوسيطة.

SELECT * FROM myTable WHERE ZIP IN (<zipcodes>)) AND bedrooms >= :minBeds

يحتوي هذا الاستعلام على سمة zipcodes تحتاج إلى تعريف وسيتم عرضها بواسطة TemplateEngine. تحتاج إلى التحقق مرة أخرى من أن TemplateEngine سيعرض هذا الكائن بطريقة تنتج استعلامًا قابلاً للاستخدام. غالبًا ما يفعلون فقط toString أو بعض المنطق الخاص مثل الشرائح الاختيارية.

minBeds هو معامل يجب ربطه وسيصبح معامل استعلام jdbc.

هناك ) أكثر من اللازم على يمين الرموز البريدية بالمناسبة.

handle.createQuery("SELECT * FROM myTable WHERE ZIP IN (<zipcodes>) AND bedrooms >= :minBeds")
  .define("zipcodes", "94536, 95035")
  .bind("minBeds", 3)
  .mapTo(MlsListing.class)
  .list());

سيقوم TemplateEngine أولاً بعرض سلسلة الاستعلام إلى
"SELECT * FROM myTable WHERE ZIP IN (94536, 95035) AND bedrooms >= :minBeds"
ثم يقوم SqlParser بتطبيق معلمات الاستعلام مثل:
"SELECT * FROM myTable WHERE ZIP IN (94536, 95035) AND bedrooms >= ?", [3]

إذا حددت List<Integer> فقد تكون النتيجة ... IN ([94536,95035]) ... أو شيء من هذا القبيل ، لذا تأكد من اختبار كيفية عرض كل نوع من العناصر قبل استخدامه.

سيكون من الأسهل إذا كان بإمكانك ربط قائمتك بدلاً من تعريفها ، لكن دعم الربط يختلف بين قواعد البيانات. لن يقبل البعض القوائم كمعلمات استعلام ، والبعض الآخر سيفسرها بشكل غير صحيح في عبارة IN (أخذ كائن القائمة كعنصر قائمة واحد بدلاً من تكرار محتوياته) ، إلخ.

TheRealMarnes شكرًا للتوضيح ، على الرغم من أن defineList("zipcodes",list) بدا فكرة جيدة ، لا يمكن استدعاؤها في قائمة فارغة / فارغة ، وهي نقطة ألم بالنسبة لي ، مثل القوائم (مثل zipcodes, cityIds.. إلخ) ديناميكيًا فقط عند قيام المستخدم بإرسال القيم. يجب أن أكتشف طريقة للحصول على bindList في وقت التشغيل. أعمل عليه...

شكرا.

أنا متأكد من أن الرجال سيحبون سماع تعليقات حول المستندات على jdbi.org وما تعلمته من توضيحي أنك لم تفعله من الموقع ، راجع للشغل.

تضمين التغريدة هل تمانع في تجميع علاقات عامة لإضافتها إلى دليل المطورين لدينا؟ يتم حاليًا تغطية TemplateEngine و SqlParser في قسم الموضوعات المتقدمة ، ولكني أشعر أن هذا القسم سيكون بمثابة مساعدة كبيرة في الدليل الأساسي (القسم 3) ، ويمكن أن يشير إلى موضوعات متقدمة لمزيد من التفاصيل.

qualidafial العمل عليه

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات